[
  {
    "path": ".Doxyfile",
    "content": "# Doxyfile 1.9.4\n\n# This file describes the settings to be used by the documentation system\n# doxygen (www.doxygen.org) for a project.\n#\n# All text after a double hash (##) is considered a comment and is placed in\n# front of the TAG it is preceding.\n#\n# All text after a single hash (#) is considered a comment and will be ignored.\n# The format is:\n# TAG = value [value, ...]\n# For lists, items can also be appended using:\n# TAG += value [value, ...]\n# Values that contain spaces should be placed between quotes (\\\" \\\").\n#\n# Note:\n#\n# Use doxygen to compare the used configuration file with the template\n# configuration file:\n# doxygen -x [configFile]\n# Use doxygen to compare the used configuration file with the template\n# configuration file without replacing the environment variables:\n# doxygen -x_noenv [configFile]\n\n#---------------------------------------------------------------------------\n# Project related configuration options\n#---------------------------------------------------------------------------\n\n# This tag specifies the encoding used for all characters in the configuration\n# file that follow. The default is UTF-8 which is also the encoding used for all\n# text before the first occurrence of this tag. Doxygen uses libiconv (or the\n# iconv built into libc) for the transcoding. See\n# https://www.gnu.org/software/libiconv/ for the list of possible encodings.\n# The default value is: UTF-8.\n\nDOXYFILE_ENCODING      = UTF-8\n\n# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by\n# double-quotes, unless you are using Doxywizard) that should identify the\n# project for which the documentation is generated. This name is used in the\n# title of most generated pages and in a few other places.\n# The default value is: My Project.\n\nPROJECT_NAME           = \"Nuklear\"\n\n# The PROJECT_NUMBER tag can be used to enter a project or revision number. This\n# could be handy for archiving the generated documentation or if some version\n# control system is used.\n\nPROJECT_NUMBER         =\n\n# Using the PROJECT_BRIEF tag one can provide an optional one line description\n# for a project that appears at the top of each page and should give viewer a\n# quick idea about the purpose of the project. Keep the description short.\n\nPROJECT_BRIEF          = \"This is a minimal-state, immediate-mode graphical user interface toolkit written in ANSI C and licensed under public domain. It was designed as a simple embeddable user interface for application and does not have any dependencies, a default render backend or OS window/input handling but instead provides a highly modular, library-based approach, with simple input state for input and draw commands describing primitive shapes as output. So instead of providing a layered library that tries to abstract over a number of platform and render backends, it focuses only on the actual UI.\"\n\n# With the PROJECT_LOGO tag one can specify a logo or an icon that is included\n# in the documentation. The maximum height of the logo should not exceed 55\n# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy\n# the logo to the output directory.\n\nPROJECT_LOGO           =\n\n# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path\n# into which the generated documentation will be written. If a relative path is\n# entered, it will be relative to the location where doxygen was started. If\n# left blank the current directory will be used.\n\nOUTPUT_DIRECTORY       = ./doc\n\n# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096\n# sub-directories (in 2 levels) under the output directory of each output format\n# and will distribute the generated files over these directories. Enabling this\n# option can be useful when feeding doxygen a huge amount of source files, where\n# putting all generated files in the same directory would otherwise causes\n# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to\n# control the number of sub-directories.\n# The default value is: NO.\n\nCREATE_SUBDIRS         = NO\n\n# Controls the number of sub-directories that will be created when\n# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every\n# level increment doubles the number of directories, resulting in 4096\n# directories at level 8 which is the default and also the maximum value. The\n# sub-directories are organized in 2 levels, the first level always has a fixed\n# numer of 16 directories.\n# Minimum value: 0, maximum value: 8, default value: 8.\n# This tag requires that the tag CREATE_SUBDIRS is set to YES.\n\nCREATE_SUBDIRS_LEVEL   = 8\n\n# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII\n# characters to appear in the names of generated files. If set to NO, non-ASCII\n# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode\n# U+3044.\n# The default value is: NO.\n\nALLOW_UNICODE_NAMES    = NO\n\n# The OUTPUT_LANGUAGE tag is used to specify the language in which all\n# documentation generated by doxygen is written. Doxygen will use this\n# information to generate all constant output in the proper language.\n# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian,\n# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English\n# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek,\n# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with\n# English messages), Korean, Korean-en (Korean with English messages), Latvian,\n# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese,\n# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish,\n# Swedish, Turkish, Ukrainian and Vietnamese.\n# The default value is: English.\n\nOUTPUT_LANGUAGE        = English\n\n# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member\n# descriptions after the members that are listed in the file and class\n# documentation (similar to Javadoc). Set to NO to disable this.\n# The default value is: YES.\n\nBRIEF_MEMBER_DESC      = YES\n\n# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief\n# description of a member or function before the detailed description\n#\n# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\n# brief descriptions will be completely suppressed.\n# The default value is: YES.\n\nREPEAT_BRIEF           = YES\n\n# This tag implements a quasi-intelligent brief description abbreviator that is\n# used to form the text in various listings. Each string in this list, if found\n# as the leading text of the brief description, will be stripped from the text\n# and the result, after processing the whole list, is used as the annotated\n# text. Otherwise, the brief description is used as-is. If left blank, the\n# following values are used ($name is automatically replaced with the name of\n# the entity):The $name class, The $name widget, The $name file, is, provides,\n# specifies, contains, represents, a, an and the.\n\nABBREVIATE_BRIEF       = \"The $name class\" \\\n                         \"The $name widget\" \\\n                         \"The $name file\" \\\n                         is \\\n                         provides \\\n                         specifies \\\n                         contains \\\n                         represents \\\n                         a \\\n                         an \\\n                         the\n\n# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\n# doxygen will generate a detailed section even if there is only a brief\n# description.\n# The default value is: NO.\n\nALWAYS_DETAILED_SEC    = NO\n\n# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all\n# inherited members of a class in the documentation of that class as if those\n# members were ordinary class members. Constructors, destructors and assignment\n# operators of the base classes will not be shown.\n# The default value is: NO.\n\nINLINE_INHERITED_MEMB  = NO\n\n# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path\n# before files name in the file list and in the header files. If set to NO the\n# shortest path that makes the file name unique will be used\n# The default value is: YES.\n\nFULL_PATH_NAMES        = YES\n\n# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.\n# Stripping is only done if one of the specified strings matches the left-hand\n# part of the path. The tag can be used to show relative paths in the file list.\n# If left blank the directory from which doxygen is run is used as the path to\n# strip.\n#\n# Note that you can specify absolute paths here, but also relative paths, which\n# will be relative from the directory where doxygen is started.\n# This tag requires that the tag FULL_PATH_NAMES is set to YES.\n\nSTRIP_FROM_PATH        =\n\n# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the\n# path mentioned in the documentation of a class, which tells the reader which\n# header file to include in order to use a class. If left blank only the name of\n# the header file containing the class definition is used. Otherwise one should\n# specify the list of include paths that are normally passed to the compiler\n# using the -I flag.\n\nSTRIP_FROM_INC_PATH    =\n\n# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but\n# less readable) file names. This can be useful is your file systems doesn't\n# support long names like on DOS, Mac, or CD-ROM.\n# The default value is: NO.\n\nSHORT_NAMES            = NO\n\n# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the\n# first line (until the first dot) of a Javadoc-style comment as the brief\n# description. If set to NO, the Javadoc-style will behave just like regular Qt-\n# style comments (thus requiring an explicit @brief command for a brief\n# description.)\n# The default value is: NO.\n\nJAVADOC_AUTOBRIEF      = YES\n\n# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line\n# such as\n# /***************\n# as being the beginning of a Javadoc-style comment \"banner\". If set to NO, the\n# Javadoc-style will behave just like regular comments and it will not be\n# interpreted by doxygen.\n# The default value is: NO.\n\nJAVADOC_BANNER         = NO\n\n# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first\n# line (until the first dot) of a Qt-style comment as the brief description. If\n# set to NO, the Qt-style will behave just like regular Qt-style comments (thus\n# requiring an explicit \\brief command for a brief description.)\n# The default value is: NO.\n\nQT_AUTOBRIEF           = YES\n\n# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a\n# multi-line C++ special comment block (i.e. a block of //! or /// comments) as\n# a brief description. This used to be the default behavior. The new default is\n# to treat a multi-line C++ comment block as a detailed description. Set this\n# tag to YES if you prefer the old behavior instead.\n#\n# Note that setting this tag to YES also means that rational rose comments are\n# not recognized any more.\n# The default value is: NO.\n\nMULTILINE_CPP_IS_BRIEF = YES\n\n# By default Python docstrings are displayed as preformatted text and doxygen's\n# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the\n# doxygen's special commands can be used and the contents of the docstring\n# documentation blocks is shown as doxygen documentation.\n# The default value is: YES.\n\nPYTHON_DOCSTRING       = YES\n\n# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the\n# documentation from any documented member that it re-implements.\n# The default value is: YES.\n\nINHERIT_DOCS           = YES\n\n# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new\n# page for each member. If set to NO, the documentation of a member will be part\n# of the file/class/namespace that contains it.\n# The default value is: NO.\n\nSEPARATE_MEMBER_PAGES  = NO\n\n# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen\n# uses this value to replace tabs by spaces in code fragments.\n# Minimum value: 1, maximum value: 16, default value: 4.\n\nTAB_SIZE               = 4\n\n# This tag can be used to specify a number of aliases that act as commands in\n# the documentation. An alias has the form:\n# name=value\n# For example adding\n# \"sideeffect=@par Side Effects:^^\"\n# will allow you to put the command \\sideeffect (or @sideeffect) in the\n# documentation, which will result in a user-defined paragraph with heading\n# \"Side Effects:\". Note that you cannot put \\n's in the value part of an alias\n# to insert newlines (in the resulting output). You can put ^^ in the value part\n# of an alias to insert a newline as if a physical newline was in the original\n# file. When you need a literal { or } or , in the value part of an alias you\n# have to escape them by means of a backslash (\\), this can lead to conflicts\n# with the commands \\{ and \\} for these it is advised to use the version @{ and\n# @} or use a double escape (\\\\{ and \\\\})\n\nALIASES                =\n\n# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources\n# only. Doxygen will then generate output that is more tailored for C. For\n# instance, some of the names that are used will be different. The list of all\n# members will be omitted, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_FOR_C  = YES\n\n# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or\n# Python sources only. Doxygen will then generate output that is more tailored\n# for that language. For instance, namespaces will be presented as packages,\n# qualified scopes will look different, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_JAVA   = NO\n\n# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran\n# sources. Doxygen will then generate output that is tailored for Fortran.\n# The default value is: NO.\n\nOPTIMIZE_FOR_FORTRAN   = NO\n\n# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL\n# sources. Doxygen will then generate output that is tailored for VHDL.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_VHDL   = NO\n\n# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice\n# sources only. Doxygen will then generate output that is more tailored for that\n# language. For instance, namespaces will be presented as modules, types will be\n# separated into more groups, etc.\n# The default value is: NO.\n\nOPTIMIZE_OUTPUT_SLICE  = NO\n\n# Doxygen selects the parser to use depending on the extension of the files it\n# parses. With this tag you can assign which parser to use for a given\n# extension. Doxygen has a built-in mapping, but you can override or extend it\n# using this tag. The format is ext=language, where ext is a file extension, and\n# language is one of the parsers supported by doxygen: IDL, Java, JavaScript,\n# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice,\n# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:\n# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser\n# tries to guess whether the code is fixed or free formatted code, this is the\n# default for Fortran type files). For instance to make doxygen treat .inc files\n# as Fortran files (default is PHP), and .f files as C (default is Fortran),\n# use: inc=Fortran f=C.\n#\n# Note: For files without extension you can use no_extension as a placeholder.\n#\n# Note that for custom extensions you also need to set FILE_PATTERNS otherwise\n# the files are not read by doxygen. When specifying no_extension you should add\n# * to the FILE_PATTERNS.\n#\n# Note see also the list of default file extension mappings.\n\nEXTENSION_MAPPING      =\n\n# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments\n# according to the Markdown format, which allows for more readable\n# documentation. See https://daringfireball.net/projects/markdown/ for details.\n# The output of markdown processing is further processed by doxygen, so you can\n# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in\n# case of backward compatibilities issues.\n# The default value is: YES.\n\nMARKDOWN_SUPPORT       = YES\n\n# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up\n# to that level are automatically included in the table of contents, even if\n# they do not have an id attribute.\n# Note: This feature currently applies only to Markdown headings.\n# Minimum value: 0, maximum value: 99, default value: 5.\n# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.\n\nTOC_INCLUDE_HEADINGS   = 5\n\n# When enabled doxygen tries to link words that correspond to documented\n# classes, or namespaces to their corresponding documentation. Such a link can\n# be prevented in individual cases by putting a % sign in front of the word or\n# globally by setting AUTOLINK_SUPPORT to NO.\n# The default value is: YES.\n\nAUTOLINK_SUPPORT       = YES\n\n# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\n# to include (a tag file for) the STL sources as input, then you should set this\n# tag to YES in order to let doxygen match functions declarations and\n# definitions whose arguments contain STL classes (e.g. func(std::string);\n# versus func(std::string) {}). This also make the inheritance and collaboration\n# diagrams that involve STL classes more complete and accurate.\n# The default value is: NO.\n\nBUILTIN_STL_SUPPORT    = NO\n\n# If you use Microsoft's C++/CLI language, you should set this option to YES to\n# enable parsing support.\n# The default value is: NO.\n\nCPP_CLI_SUPPORT        = NO\n\n# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:\n# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen\n# will parse them like normal C++ but will assume all classes use public instead\n# of private inheritance when no explicit protection keyword is present.\n# The default value is: NO.\n\nSIP_SUPPORT            = NO\n\n# For Microsoft's IDL there are propget and propput attributes to indicate\n# getter and setter methods for a property. Setting this option to YES will make\n# doxygen to replace the get and set methods by a property in the documentation.\n# This will only work if the methods are indeed getting or setting a simple\n# type. If this is not the case, or you want to show the methods anyway, you\n# should set this option to NO.\n# The default value is: YES.\n\nIDL_PROPERTY_SUPPORT   = YES\n\n# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\n# tag is set to YES then doxygen will reuse the documentation of the first\n# member in the group (if any) for the other members of the group. By default\n# all members of a group must be documented explicitly.\n# The default value is: NO.\n\nDISTRIBUTE_GROUP_DOC   = NO\n\n# If one adds a struct or class to a group and this option is enabled, then also\n# any nested class or struct is added to the same group. By default this option\n# is disabled and one has to add nested compounds explicitly via \\ingroup.\n# The default value is: NO.\n\nGROUP_NESTED_COMPOUNDS = NO\n\n# Set the SUBGROUPING tag to YES to allow class member groups of the same type\n# (for instance a group of public functions) to be put as a subgroup of that\n# type (e.g. under the Public Functions section). Set it to NO to prevent\n# subgrouping. Alternatively, this can be done per class using the\n# \\nosubgrouping command.\n# The default value is: YES.\n\nSUBGROUPING            = YES\n\n# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions\n# are shown inside the group in which they are included (e.g. using \\ingroup)\n# instead of on a separate page (for HTML and Man pages) or section (for LaTeX\n# and RTF).\n#\n# Note that this feature does not work in combination with\n# SEPARATE_MEMBER_PAGES.\n# The default value is: NO.\n\nINLINE_GROUPED_CLASSES = NO\n\n# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions\n# with only public data fields or simple typedef fields will be shown inline in\n# the documentation of the scope in which they are defined (i.e. file,\n# namespace, or group documentation), provided this scope is documented. If set\n# to NO, structs, classes, and unions are shown on a separate page (for HTML and\n# Man pages) or section (for LaTeX and RTF).\n# The default value is: NO.\n\nINLINE_SIMPLE_STRUCTS  = NO\n\n# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or\n# enum is documented as struct, union, or enum with the name of the typedef. So\n# typedef struct TypeS {} TypeT, will appear in the documentation as a struct\n# with name TypeT. When disabled the typedef will appear as a member of a file,\n# namespace, or class. And the struct will be named TypeS. This can typically be\n# useful for C code in case the coding convention dictates that all compound\n# types are typedef'ed and only the typedef is referenced, never the tag name.\n# The default value is: NO.\n\nTYPEDEF_HIDES_STRUCT   = NO\n\n# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This\n# cache is used to resolve symbols given their name and scope. Since this can be\n# an expensive process and often the same symbol appears multiple times in the\n# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small\n# doxygen will become slower. If the cache is too large, memory is wasted. The\n# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range\n# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536\n# symbols. At the end of a run doxygen will report the cache usage and suggest\n# the optimal cache size from a speed point of view.\n# Minimum value: 0, maximum value: 9, default value: 0.\n\nLOOKUP_CACHE_SIZE      = 0\n\n# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use\n# during processing. When set to 0 doxygen will based this on the number of\n# cores available in the system. You can set it explicitly to a value larger\n# than 0 to get more control over the balance between CPU load and processing\n# speed. At this moment only the input processing can be done using multiple\n# threads. Since this is still an experimental feature the default is set to 1,\n# which effectively disables parallel processing. Please report any issues you\n# encounter. Generating dot graphs in parallel is controlled by the\n# DOT_NUM_THREADS setting.\n# Minimum value: 0, maximum value: 32, default value: 1.\n\nNUM_PROC_THREADS       = 0\n\n#---------------------------------------------------------------------------\n# Build related configuration options\n#---------------------------------------------------------------------------\n\n# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in\n# documentation are documented, even if no documentation was available. Private\n# class members and static file members will be hidden unless the\n# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.\n# Note: This will also disable the warnings about undocumented members that are\n# normally produced when WARNINGS is set to YES.\n# The default value is: NO.\n\nEXTRACT_ALL            = NO\n\n# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will\n# be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIVATE        = NO\n\n# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual\n# methods of a class will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PRIV_VIRTUAL   = NO\n\n# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal\n# scope will be included in the documentation.\n# The default value is: NO.\n\nEXTRACT_PACKAGE        = NO\n\n# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be\n# included in the documentation.\n# The default value is: NO.\n\nEXTRACT_STATIC         = YES\n\n# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined\n# locally in source files will be included in the documentation. If set to NO,\n# only classes defined in header files are included. Does not have any effect\n# for Java sources.\n# The default value is: YES.\n\nEXTRACT_LOCAL_CLASSES  = YES\n\n# This flag is only useful for Objective-C code. If set to YES, local methods,\n# which are defined in the implementation section but not in the interface are\n# included in the documentation. If set to NO, only methods in the interface are\n# included.\n# The default value is: NO.\n\nEXTRACT_LOCAL_METHODS  = NO\n\n# If this flag is set to YES, the members of anonymous namespaces will be\n# extracted and appear in the documentation as a namespace called\n# 'anonymous_namespace{file}', where file will be replaced with the base name of\n# the file that contains the anonymous namespace. By default anonymous namespace\n# are hidden.\n# The default value is: NO.\n\nEXTRACT_ANON_NSPACES   = NO\n\n# If this flag is set to YES, the name of an unnamed parameter in a declaration\n# will be determined by the corresponding definition. By default unnamed\n# parameters remain unnamed in the output.\n# The default value is: YES.\n\nRESOLVE_UNNAMED_PARAMS = YES\n\n# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all\n# undocumented members inside documented classes or files. If set to NO these\n# members will be included in the various overviews, but no documentation\n# section is generated. This option has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_MEMBERS     = NO\n\n# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all\n# undocumented classes that are normally visible in the class hierarchy. If set\n# to NO, these classes will be included in the various overviews. This option\n# has no effect if EXTRACT_ALL is enabled.\n# The default value is: NO.\n\nHIDE_UNDOC_CLASSES     = NO\n\n# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend\n# declarations. If set to NO, these declarations will be included in the\n# documentation.\n# The default value is: NO.\n\nHIDE_FRIEND_COMPOUNDS  = NO\n\n# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any\n# documentation blocks found inside the body of a function. If set to NO, these\n# blocks will be appended to the function's detailed documentation block.\n# The default value is: NO.\n\nHIDE_IN_BODY_DOCS      = NO\n\n# The INTERNAL_DOCS tag determines if documentation that is typed after a\n# \\internal command is included. If the tag is set to NO then the documentation\n# will be excluded. Set it to YES to include the internal documentation.\n# The default value is: NO.\n\nINTERNAL_DOCS          = NO\n\n# With the correct setting of option CASE_SENSE_NAMES doxygen will better be\n# able to match the capabilities of the underlying filesystem. In case the\n# filesystem is case sensitive (i.e. it supports files in the same directory\n# whose names only differ in casing), the option must be set to YES to properly\n# deal with such files in case they appear in the input. For filesystems that\n# are not case sensitive the option should be set to NO to properly deal with\n# output files written for symbols that only differ in casing, such as for two\n# classes, one named CLASS and the other named Class, and to also support\n# references to files without having to specify the exact matching casing. On\n# Windows (including Cygwin) and MacOS, users should typically set this option\n# to NO, whereas on Linux or other Unix flavors it should typically be set to\n# YES.\n# The default value is: system dependent.\n\nCASE_SENSE_NAMES       = YES\n\n# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with\n# their full class and namespace scopes in the documentation. If set to YES, the\n# scope will be hidden.\n# The default value is: NO.\n\nHIDE_SCOPE_NAMES       = NO\n\n# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will\n# append additional text to a page's title, such as Class Reference. If set to\n# YES the compound reference will be hidden.\n# The default value is: NO.\n\nHIDE_COMPOUND_REFERENCE= NO\n\n# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class\n# will show which file needs to be included to use the class.\n# The default value is: YES.\n\nSHOW_HEADERFILE        = YES\n\n# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of\n# the files that are included by a file in the documentation of that file.\n# The default value is: YES.\n\nSHOW_INCLUDE_FILES     = YES\n\n# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each\n# grouped member an include statement to the documentation, telling the reader\n# which file to include in order to use the member.\n# The default value is: NO.\n\nSHOW_GROUPED_MEMB_INC  = NO\n\n# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include\n# files with double quotes in the documentation rather than with sharp brackets.\n# The default value is: NO.\n\nFORCE_LOCAL_INCLUDES   = NO\n\n# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the\n# documentation for inline members.\n# The default value is: YES.\n\nINLINE_INFO            = YES\n\n# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the\n# (detailed) documentation of file and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order.\n# The default value is: YES.\n\nSORT_MEMBER_DOCS       = YES\n\n# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief\n# descriptions of file, namespace and class members alphabetically by member\n# name. If set to NO, the members will appear in declaration order. Note that\n# this will also influence the order of the classes in the class list.\n# The default value is: NO.\n\nSORT_BRIEF_DOCS        = NO\n\n# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the\n# (brief and detailed) documentation of class members so that constructors and\n# destructors are listed first. If set to NO the constructors will appear in the\n# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.\n# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief\n# member documentation.\n# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting\n# detailed member documentation.\n# The default value is: NO.\n\nSORT_MEMBERS_CTORS_1ST = NO\n\n# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy\n# of group names into alphabetical order. If set to NO the group names will\n# appear in their defined order.\n# The default value is: NO.\n\nSORT_GROUP_NAMES       = NO\n\n# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by\n# fully-qualified names, including namespaces. If set to NO, the class list will\n# be sorted only by class name, not including the namespace part.\n# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\n# Note: This option applies only to the class list, not to the alphabetical\n# list.\n# The default value is: NO.\n\nSORT_BY_SCOPE_NAME     = NO\n\n# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper\n# type resolution of all parameters of a function it will reject a match between\n# the prototype and the implementation of a member function even if there is\n# only one candidate or it is obvious which candidate to choose by doing a\n# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still\n# accept a match between prototype and implementation in such cases.\n# The default value is: NO.\n\nSTRICT_PROTO_MATCHING  = NO\n\n# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo\n# list. This list is created by putting \\todo commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TODOLIST      = YES\n\n# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test\n# list. This list is created by putting \\test commands in the documentation.\n# The default value is: YES.\n\nGENERATE_TESTLIST      = YES\n\n# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug\n# list. This list is created by putting \\bug commands in the documentation.\n# The default value is: YES.\n\nGENERATE_BUGLIST       = YES\n\n# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)\n# the deprecated list. This list is created by putting \\deprecated commands in\n# the documentation.\n# The default value is: YES.\n\nGENERATE_DEPRECATEDLIST= YES\n\n# The ENABLED_SECTIONS tag can be used to enable conditional documentation\n# sections, marked by \\if <section_label> ... \\endif and \\cond <section_label>\n# ... \\endcond blocks.\n\nENABLED_SECTIONS       =\n\n# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the\n# initial value of a variable or macro / define can have for it to appear in the\n# documentation. If the initializer consists of more lines than specified here\n# it will be hidden. Use a value of 0 to hide initializers completely. The\n# appearance of the value of individual variables and macros / defines can be\n# controlled using \\showinitializer or \\hideinitializer command in the\n# documentation regardless of this setting.\n# Minimum value: 0, maximum value: 10000, default value: 30.\n\nMAX_INITIALIZER_LINES  = 30\n\n# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at\n# the bottom of the documentation of classes and structs. If set to YES, the\n# list will mention the files that were used to generate the documentation.\n# The default value is: YES.\n\nSHOW_USED_FILES        = YES\n\n# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This\n# will remove the Files entry from the Quick Index and from the Folder Tree View\n# (if specified).\n# The default value is: YES.\n\nSHOW_FILES             = YES\n\n# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces\n# page. This will remove the Namespaces entry from the Quick Index and from the\n# Folder Tree View (if specified).\n# The default value is: YES.\n\nSHOW_NAMESPACES        = YES\n\n# The FILE_VERSION_FILTER tag can be used to specify a program or script that\n# doxygen should invoke to get the current version for each file (typically from\n# the version control system). Doxygen will invoke the program by executing (via\n# popen()) the command command input-file, where command is the value of the\n# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided\n# by doxygen. Whatever the program writes to standard output is used as the file\n# version. For an example see the documentation.\n\nFILE_VERSION_FILTER    =\n\n# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\n# by doxygen. The layout file controls the global structure of the generated\n# output files in an output format independent way. To create the layout file\n# that represents doxygen's defaults, run doxygen with the -l option. You can\n# optionally specify a file name after the option, if omitted DoxygenLayout.xml\n# will be used as the name of the layout file. See also section \"Changing the\n# layout of pages\" for information.\n#\n# Note that if you run doxygen from a directory containing a file called\n# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE\n# tag is left empty.\n\nLAYOUT_FILE            =\n\n# The CITE_BIB_FILES tag can be used to specify one or more bib files containing\n# the reference definitions. This must be a list of .bib files. The .bib\n# extension is automatically appended if omitted. This requires the bibtex tool\n# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.\n# For LaTeX the style of the bibliography can be controlled using\n# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the\n# search path. See also \\cite for info how to create references.\n\nCITE_BIB_FILES         =\n\n#---------------------------------------------------------------------------\n# Configuration options related to warning and progress messages\n#---------------------------------------------------------------------------\n\n# The QUIET tag can be used to turn on/off the messages that are generated to\n# standard output by doxygen. If QUIET is set to YES this implies that the\n# messages are off.\n# The default value is: NO.\n\nQUIET                  = NO\n\n# The WARNINGS tag can be used to turn on/off the warning messages that are\n# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES\n# this implies that the warnings are on.\n#\n# Tip: Turn warnings on while writing the documentation.\n# The default value is: YES.\n\nWARNINGS               = YES\n\n# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate\n# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag\n# will automatically be disabled.\n# The default value is: YES.\n\nWARN_IF_UNDOCUMENTED   = YES\n\n# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for\n# potential errors in the documentation, such as documenting some parameters in\n# a documented function twice, or documenting parameters that don't exist or\n# using markup commands wrongly.\n# The default value is: YES.\n\nWARN_IF_DOC_ERROR      = YES\n\n# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete\n# function parameter documentation. If set to NO, doxygen will accept that some\n# parameters have no documentation without warning.\n# The default value is: YES.\n\nWARN_IF_INCOMPLETE_DOC = YES\n\n# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that\n# are documented, but have no documentation for their parameters or return\n# value. If set to NO, doxygen will only warn about wrong parameter\n# documentation, but not about the absence of documentation. If EXTRACT_ALL is\n# set to YES then this flag will automatically be disabled. See also\n# WARN_IF_INCOMPLETE_DOC\n# The default value is: NO.\n\nWARN_NO_PARAMDOC       = YES\n\n# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when\n# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS\n# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but\n# at the end of the doxygen process doxygen will return with a non-zero status.\n# Possible values are: NO, YES and FAIL_ON_WARNINGS.\n# The default value is: NO.\n\nWARN_AS_ERROR          = NO\n\n# The WARN_FORMAT tag determines the format of the warning messages that doxygen\n# can produce. The string should contain the $file, $line, and $text tags, which\n# will be replaced by the file and line number from which the warning originated\n# and the warning text. Optionally the format may contain $version, which will\n# be replaced by the version of the file (if it could be obtained via\n# FILE_VERSION_FILTER)\n# See also: WARN_LINE_FORMAT\n# The default value is: $file:$line: $text.\n\nWARN_FORMAT            = \"$file:$line: $text\"\n\n# In the $text part of the WARN_FORMAT command it is possible that a reference\n# to a more specific place is given. To make it easier to jump to this place\n# (outside of doxygen) the user can define a custom \"cut\" / \"paste\" string.\n# Example:\n# WARN_LINE_FORMAT = \"'vi $file +$line'\"\n# See also: WARN_FORMAT\n# The default value is: at line $line of file $file.\n\nWARN_LINE_FORMAT       = \"at line $line of file $file\"\n\n# The WARN_LOGFILE tag can be used to specify a file to which warning and error\n# messages should be written. If left blank the output is written to standard\n# error (stderr). In case the file specified cannot be opened for writing the\n# warning and error messages are written to standard error. When as file - is\n# specified the warning and error messages are written to standard output\n# (stdout).\n\nWARN_LOGFILE           =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the input files\n#---------------------------------------------------------------------------\n\n# The INPUT tag is used to specify the files and/or directories that contain\n# documented source files. You may enter file names like myfile.cpp or\n# directories like /usr/src/myproject. Separate the files or directories with\n# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING\n# Note: If this tag is empty the current directory is searched.\n\nINPUT                  =    \"./src\" \\\n                            \"./src/HEADER.md\"\n\n\n\n# This tag can be used to specify the character encoding of the source files\n# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses\n# libiconv (or the iconv built into libc) for the transcoding. See the libiconv\n# documentation (see:\n# https://www.gnu.org/software/libiconv/) for the list of possible encodings.\n# The default value is: UTF-8.\n\nINPUT_ENCODING         = UTF-8\n\n# If the value of the INPUT tag contains directories, you can use the\n# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and\n# *.h) to filter out the source-files in the directories.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# read by doxygen.\n#\n# Note the list of default checked file patterns might differ from the list of\n# default file extension mappings.\n#\n# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,\n# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,\n# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml,\n# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C\n# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd,\n# *.vhdl, *.ucf, *.qsf and *.ice.\n\nFILE_PATTERNS          = *.c \\\n                         *.cc \\\n                         *.cxx \\\n                         *.cpp \\\n                         *.c++ \\\n                         *.java \\\n                         *.ii \\\n                         *.ixx \\\n                         *.ipp \\\n                         *.i++ \\\n                         *.inl \\\n                         *.idl \\\n                         *.ddl \\\n                         *.odl \\\n                         *.h \\\n                         *.hh \\\n                         *.hxx \\\n                         *.hpp \\\n                         *.h++ \\\n                         *.l \\\n                         *.cs \\\n                         *.d \\\n                         *.php \\\n                         *.php4 \\\n                         *.php5 \\\n                         *.phtml \\\n                         *.inc \\\n                         *.m \\\n                         *.markdown \\\n                         *.md \\\n                         *.mm \\\n                         *.dox \\\n                         *.py \\\n                         *.pyw \\\n                         *.f90 \\\n                         *.f95 \\\n                         *.f03 \\\n                         *.f08 \\\n                         *.f18 \\\n                         *.f \\\n                         *.for \\\n                         *.vhd \\\n                         *.vhdl \\\n                         *.ucf \\\n                         *.qsf \\\n                         *.ice\n\n# The RECURSIVE tag can be used to specify whether or not subdirectories should\n# be searched for input files as well.\n# The default value is: NO.\n\nRECURSIVE              = NO\n\n# The EXCLUDE tag can be used to specify files and/or directories that should be\n# excluded from the INPUT source files. This way you can easily exclude a\n# subdirectory from a directory tree whose root is specified with the INPUT tag.\n#\n# Note that relative paths are relative to the directory from which doxygen is\n# run.\n\nEXCLUDE                = \"./src/Readme.md\" \\\n                            \"./src/paq.sh\" \\\n                            \"./src/paq.bat\"\n\n# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or\n# directories that are symbolic links (a Unix file system feature) are excluded\n# from the input.\n# The default value is: NO.\n\nEXCLUDE_SYMLINKS       = NO\n\n# If the value of the INPUT tag contains directories, you can use the\n# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\n# certain files from those directories.\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories for example use the pattern */test/*\n\nEXCLUDE_PATTERNS       =\n\n# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\n# (namespaces, classes, functions, etc.) that should be excluded from the\n# output. The symbol name can be a fully qualified name, a word, or if the\n# wildcard * is used, a substring. Examples: ANamespace, AClass,\n# ANamespace::AClass, ANamespace::*Test\n#\n# Note that the wildcards are matched against the file with absolute path, so to\n# exclude all test directories use the pattern */test/*\n\nEXCLUDE_SYMBOLS        =\n\n# The EXAMPLE_PATH tag can be used to specify one or more files or directories\n# that contain example code fragments that are included (see the \\include\n# command).\n\nEXAMPLE_PATH           =\n\n# If the value of the EXAMPLE_PATH tag contains directories, you can use the\n# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and\n# *.h) to filter out the source-files in the directories. If left blank all\n# files are included.\n\nEXAMPLE_PATTERNS       = *\n\n# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\n# searched for input files to be used with the \\include or \\dontinclude commands\n# irrespective of the value of the RECURSIVE tag.\n# The default value is: NO.\n\nEXAMPLE_RECURSIVE      = NO\n\n# The IMAGE_PATH tag can be used to specify one or more files or directories\n# that contain images that are to be included in the documentation (see the\n# \\image command).\n\nIMAGE_PATH             =\n\n# The INPUT_FILTER tag can be used to specify a program that doxygen should\n# invoke to filter for each input file. Doxygen will invoke the filter program\n# by executing (via popen()) the command:\n#\n# <filter> <input-file>\n#\n# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the\n# name of an input file. Doxygen will then use the output that the filter\n# program writes to standard output. If FILTER_PATTERNS is specified, this tag\n# will be ignored.\n#\n# Note that the filter must not add or remove lines; it is applied before the\n# code is scanned, but not when the output code is generated. If lines are added\n# or removed, the anchors will not be placed correctly.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nINPUT_FILTER           =\n\n# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\n# basis. Doxygen will compare the file name with each pattern and apply the\n# filter if there is a match. The filters are a list of the form: pattern=filter\n# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how\n# filters are used. If the FILTER_PATTERNS tag is empty or if none of the\n# patterns match the file name, INPUT_FILTER is applied.\n#\n# Note that for custom extensions or not directly supported extensions you also\n# need to set EXTENSION_MAPPING for the extension otherwise the files are not\n# properly processed by doxygen.\n\nFILTER_PATTERNS        =\n\n# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\n# INPUT_FILTER) will also be used to filter the input files that are used for\n# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).\n# The default value is: NO.\n\nFILTER_SOURCE_FILES    = NO\n\n# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file\n# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and\n# it is also possible to disable source filtering for a specific pattern using\n# *.ext= (so without naming a filter).\n# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.\n\nFILTER_SOURCE_PATTERNS =\n\n# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that\n# is part of the input, its contents will be placed on the main page\n# (index.html). This can be useful if you have a project on for instance GitHub\n# and want to reuse the introduction page also for the doxygen output.\n\nUSE_MDFILE_AS_MAINPAGE = src/HEADER.md\n\n#---------------------------------------------------------------------------\n# Configuration options related to source browsing\n#---------------------------------------------------------------------------\n\n# If the SOURCE_BROWSER tag is set to YES then a list of source files will be\n# generated. Documented entities will be cross-referenced with these sources.\n#\n# Note: To get rid of all source code in the generated output, make sure that\n# also VERBATIM_HEADERS is set to NO.\n# The default value is: NO.\n\nSOURCE_BROWSER         = YES\n\n# Setting the INLINE_SOURCES tag to YES will include the body of functions,\n# classes and enums directly into the documentation.\n# The default value is: NO.\n\nINLINE_SOURCES         = NO\n\n# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any\n# special comment blocks from generated source code fragments. Normal C, C++ and\n# Fortran comments will always remain visible.\n# The default value is: YES.\n\nSTRIP_CODE_COMMENTS    = YES\n\n# If the REFERENCED_BY_RELATION tag is set to YES then for each documented\n# entity all documented functions referencing it will be listed.\n# The default value is: NO.\n\nREFERENCED_BY_RELATION = YES\n\n# If the REFERENCES_RELATION tag is set to YES then for each documented function\n# all documented entities called/used by that function will be listed.\n# The default value is: NO.\n\nREFERENCES_RELATION    = YES\n\n# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set\n# to YES then the hyperlinks from functions in REFERENCES_RELATION and\n# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will\n# link to the documentation.\n# The default value is: YES.\n\nREFERENCES_LINK_SOURCE = YES\n\n# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the\n# source code will show a tooltip with additional information such as prototype,\n# brief description and links to the definition and documentation. Since this\n# will make the HTML file larger and loading of large files a bit slower, you\n# can opt to disable this feature.\n# The default value is: YES.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nSOURCE_TOOLTIPS        = YES\n\n# If the USE_HTAGS tag is set to YES then the references to source code will\n# point to the HTML generated by the htags(1) tool instead of doxygen built-in\n# source browser. The htags tool is part of GNU's global source tagging system\n# (see https://www.gnu.org/software/global/global.html). You will need version\n# 4.8.6 or higher.\n#\n# To use it do the following:\n# - Install the latest version of global\n# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file\n# - Make sure the INPUT points to the root of the source tree\n# - Run doxygen as normal\n#\n# Doxygen will invoke htags (and that will in turn invoke gtags), so these\n# tools must be available from the command line (i.e. in the search path).\n#\n# The result: instead of the source browser generated by doxygen, the links to\n# source code will now point to the output of htags.\n# The default value is: NO.\n# This tag requires that the tag SOURCE_BROWSER is set to YES.\n\nUSE_HTAGS              = NO\n\n# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a\n# verbatim copy of the header file for each class for which an include is\n# specified. Set to NO to disable this.\n# See also: Section \\class.\n# The default value is: YES.\n\nVERBATIM_HEADERS       = YES\n\n# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the\n# clang parser (see:\n# http://clang.llvm.org/) for more accurate parsing at the cost of reduced\n# performance. This can be particularly helpful with template rich C++ code for\n# which doxygen's built-in parser lacks the necessary type information.\n# Note: The availability of this option depends on whether or not doxygen was\n# generated with the -Duse_libclang=ON option for CMake.\n# The default value is: NO.\n\nCLANG_ASSISTED_PARSING = NO\n\n# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS\n# tag is set to YES then doxygen will add the directory of each input to the\n# include path.\n# The default value is: YES.\n# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.\n\nCLANG_ADD_INC_PATHS    = YES\n\n# If clang assisted parsing is enabled you can provide the compiler with command\n# line options that you would normally use when invoking the compiler. Note that\n# the include paths will already be set by doxygen for the files and directories\n# specified with INPUT and INCLUDE_PATH.\n# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.\n\nCLANG_OPTIONS          =\n\n# If clang assisted parsing is enabled you can provide the clang parser with the\n# path to the directory containing a file called compile_commands.json. This\n# file is the compilation database (see:\n# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the\n# options used when the source files were built. This is equivalent to\n# specifying the -p option to a clang tool, such as clang-check. These options\n# will then be passed to the parser. Any options specified with CLANG_OPTIONS\n# will be added as well.\n# Note: The availability of this option depends on whether or not doxygen was\n# generated with the -Duse_libclang=ON option for CMake.\n\nCLANG_DATABASE_PATH    =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the alphabetical class index\n#---------------------------------------------------------------------------\n\n# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all\n# compounds will be generated. Enable this if the project contains a lot of\n# classes, structs, unions or interfaces.\n# The default value is: YES.\n\nALPHABETICAL_INDEX     = YES\n\n# In case all classes in a project start with a common prefix, all classes will\n# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag\n# can be used to specify a prefix (or a list of prefixes) that should be ignored\n# while generating the index headers.\n# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.\n\nIGNORE_PREFIX          =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the HTML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output\n# The default value is: YES.\n\nGENERATE_HTML          = YES\n\n# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_OUTPUT            = html\n\n# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each\n# generated HTML page (for example: .htm, .php, .asp).\n# The default value is: .html.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FILE_EXTENSION    = .html\n\n# The HTML_HEADER tag can be used to specify a user-defined HTML header file for\n# each generated HTML page. If the tag is left blank doxygen will generate a\n# standard header.\n#\n# To get valid HTML the header file that includes any scripts and style sheets\n# that doxygen needs, which is dependent on the configuration options used (e.g.\n# the setting GENERATE_TREEVIEW). It is highly recommended to start with a\n# default header using\n# doxygen -w html new_header.html new_footer.html new_stylesheet.css\n# YourConfigFile\n# and then modify the file new_header.html. See also section \"Doxygen usage\"\n# for information on how to generate the default header that doxygen normally\n# uses.\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of doxygen. For a description\n# of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_HEADER            =\n\n# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each\n# generated HTML page. If the tag is left blank doxygen will generate a standard\n# footer. See HTML_HEADER for more information on how to generate a default\n# footer and what special commands can be used inside the footer. See also\n# section \"Doxygen usage\" for information on how to generate the default footer\n# that doxygen normally uses.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FOOTER            =\n\n# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style\n# sheet that is used by each HTML page. It can be used to fine-tune the look of\n# the HTML output. If left blank doxygen will generate a default style sheet.\n# See also section \"Doxygen usage\" for information on how to generate the style\n# sheet that doxygen normally uses.\n# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as\n# it is more robust and this tag (HTML_STYLESHEET) will in the future become\n# obsolete.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_STYLESHEET        =\n\n# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# cascading style sheets that are included after the standard style sheets\n# created by doxygen. Using this option one can overrule certain style aspects.\n# This is preferred over using HTML_STYLESHEET since it does not replace the\n# standard style sheet and is therefore more robust against future updates.\n# Doxygen will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list). For an example see the documentation.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_STYLESHEET  = ./doc/doxygen-awesome-css/doxygen-awesome.css\n\n# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the HTML output directory. Note\n# that these files will be copied to the base HTML output directory. Use the\n# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these\n# files. In the HTML_STYLESHEET file, use the file name only. Also note that the\n# files will be copied as-is; there are no commands or markers available.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_EXTRA_FILES       =\n\n# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen\n# will adjust the colors in the style sheet and background images according to\n# this color. Hue is specified as an angle on a color-wheel, see\n# https://en.wikipedia.org/wiki/Hue for more information. For instance the value\n# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300\n# purple, and 360 is red again.\n# Minimum value: 0, maximum value: 359, default value: 220.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_HUE    = 220\n\n# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors\n# in the HTML output. For a value of 0 the output will use gray-scales only. A\n# value of 255 will produce the most vivid colors.\n# Minimum value: 0, maximum value: 255, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_SAT    = 100\n\n# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the\n# luminance component of the colors in the HTML output. Values below 100\n# gradually make the output lighter, whereas values above 100 make the output\n# darker. The value divided by 100 is the actual gamma applied, so 80 represents\n# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not\n# change the gamma.\n# Minimum value: 40, maximum value: 240, default value: 80.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_COLORSTYLE_GAMMA  = 80\n\n# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML\n# page will contain the date and time when the page was generated. Setting this\n# to YES can help to show when doxygen was last run and thus if the\n# documentation is up to date.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_TIMESTAMP         = NO\n\n# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML\n# documentation will contain a main index with vertical navigation menus that\n# are dynamically created via JavaScript. If disabled, the navigation index will\n# consists of multiple levels of tabs that are statically embedded in every HTML\n# page. Disable this option to support browsers that do not have JavaScript,\n# like the Qt help browser.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_MENUS     = YES\n\n# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\n# documentation will contain sections that can be hidden and shown after the\n# page has loaded.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_DYNAMIC_SECTIONS  = NO\n\n# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries\n# shown in the various tree structured indices initially; the user can expand\n# and collapse entries dynamically later on. Doxygen will expand the tree to\n# such a level that at most the specified number of entries are visible (unless\n# a fully collapsed tree already exceeds this amount). So setting the number of\n# entries 1 will produce a full collapsed tree by default. 0 is a special value\n# representing an infinite number of entries and will result in a full expanded\n# tree by default.\n# Minimum value: 0, maximum value: 9999, default value: 100.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_INDEX_NUM_ENTRIES = 100\n\n# If the GENERATE_DOCSET tag is set to YES, additional index files will be\n# generated that can be used as input for Apple's Xcode 3 integrated development\n# environment (see:\n# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To\n# create a documentation set, doxygen will generate a Makefile in the HTML\n# output directory. Running make will produce the docset in that directory and\n# running make install will install the docset in\n# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at\n# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy\n# genXcode/_index.html for more information.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_DOCSET        = NO\n\n# This tag determines the name of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# The default value is: Doxygen generated docs.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDNAME        = \"Doxygen generated docs\"\n\n# This tag determines the URL of the docset feed. A documentation feed provides\n# an umbrella under which multiple documentation sets from a single provider\n# (such as a company or product suite) can be grouped.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_FEEDURL         =\n\n# This tag specifies a string that should uniquely identify the documentation\n# set bundle. This should be a reverse domain-name style string, e.g.\n# com.mycompany.MyDocSet. Doxygen will append .docset to the name.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_BUNDLE_ID       = org.doxygen.Project\n\n# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify\n# the documentation publisher. This should be a reverse domain-name style\n# string, e.g. com.mycompany.MyDocSet.documentation.\n# The default value is: org.doxygen.Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_ID    = org.doxygen.Publisher\n\n# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.\n# The default value is: Publisher.\n# This tag requires that the tag GENERATE_DOCSET is set to YES.\n\nDOCSET_PUBLISHER_NAME  = Publisher\n\n# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three\n# additional HTML index files: index.hhp, index.hhc, and index.hhk. The\n# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop\n# on Windows. In the beginning of 2021 Microsoft took the original page, with\n# a.o. the download links, offline the HTML help workshop was already many years\n# in maintenance mode). You can download the HTML help workshop from the web\n# archives at Installation executable (see:\n# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo\n# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe).\n#\n# The HTML Help Workshop contains a compiler that can convert all HTML output\n# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML\n# files are now used as the Windows 98 help format, and will replace the old\n# Windows help format (.hlp) on all Windows platforms in the future. Compressed\n# HTML files also contain an index, a table of contents, and you can search for\n# words in the documentation. The HTML workshop also contains a viewer for\n# compressed HTML files.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_HTMLHELP      = NO\n\n# The CHM_FILE tag can be used to specify the file name of the resulting .chm\n# file. You can add a path in front of the file if the result should not be\n# written to the html output directory.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_FILE               =\n\n# The HHC_LOCATION tag can be used to specify the location (absolute path\n# including file name) of the HTML help compiler (hhc.exe). If non-empty,\n# doxygen will try to run the HTML help compiler on the generated index.hhp.\n# The file has to be specified with full path.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nHHC_LOCATION           =\n\n# The GENERATE_CHI flag controls if a separate .chi index file is generated\n# (YES) or that it should be included in the main .chm file (NO).\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nGENERATE_CHI           = NO\n\n# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)\n# and project file content.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nCHM_INDEX_ENCODING     =\n\n# The BINARY_TOC flag controls whether a binary table of contents is generated\n# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it\n# enables the Previous and Next buttons.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nBINARY_TOC             = NO\n\n# The TOC_EXPAND flag can be set to YES to add extra items for group members to\n# the table of contents of the HTML help documentation and to the tree view.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTMLHELP is set to YES.\n\nTOC_EXPAND             = NO\n\n# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\n# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that\n# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help\n# (.qch) of the generated HTML documentation.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_QHP           = NO\n\n# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify\n# the file name of the resulting .qch file. The path specified is relative to\n# the HTML output folder.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQCH_FILE               =\n\n# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help\n# Project output. For more information please see Qt Help Project / Namespace\n# (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_NAMESPACE          = org.doxygen.Project\n\n# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt\n# Help Project output. For more information please see Qt Help Project / Virtual\n# Folders (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders).\n# The default value is: doc.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_VIRTUAL_FOLDER     = doc\n\n# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom\n# filter to add. For more information please see Qt Help Project / Custom\n# Filters (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_NAME   =\n\n# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the\n# custom filter to add. For more information please see Qt Help Project / Custom\n# Filters (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_CUST_FILTER_ATTRS  =\n\n# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\n# project's filter section matches. Qt Help Project / Filter Attributes (see:\n# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHP_SECT_FILTER_ATTRS  =\n\n# The QHG_LOCATION tag can be used to specify the location (absolute path\n# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to\n# run qhelpgenerator on the generated .qhp file.\n# This tag requires that the tag GENERATE_QHP is set to YES.\n\nQHG_LOCATION           =\n\n# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be\n# generated, together with the HTML files, they form an Eclipse help plugin. To\n# install this plugin and make it available under the help contents menu in\n# Eclipse, the contents of the directory containing the HTML and XML files needs\n# to be copied into the plugins directory of eclipse. The name of the directory\n# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.\n# After copying Eclipse needs to be restarted before the help appears.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_ECLIPSEHELP   = NO\n\n# A unique identifier for the Eclipse help plugin. When installing the plugin\n# the directory name containing the HTML and XML files should also have this\n# name. Each documentation set should have its own identifier.\n# The default value is: org.doxygen.Project.\n# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.\n\nECLIPSE_DOC_ID         = org.doxygen.Project\n\n# If you want full control over the layout of the generated HTML pages it might\n# be necessary to disable the index and replace it with your own. The\n# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top\n# of each HTML page. A value of NO enables the index and the value YES disables\n# it. Since the tabs in the index contain the same information as the navigation\n# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nDISABLE_INDEX          = YES\n\n# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\n# structure should be generated to display hierarchical information. If the tag\n# value is set to YES, a side panel will be generated containing a tree-like\n# index structure (just like the one that is generated for HTML Help). For this\n# to work a browser that supports JavaScript, DHTML, CSS and frames is required\n# (i.e. any modern browser). Windows users are probably better off using the\n# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can\n# further fine tune the look of the index (see \"Fine-tuning the output\"). As an\n# example, the default style sheet generated by doxygen has an example that\n# shows how to put an image at the root of the tree instead of the PROJECT_NAME.\n# Since the tree basically has the same information as the tab index, you could\n# consider setting DISABLE_INDEX to YES when enabling this option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nGENERATE_TREEVIEW      = YES\n\n# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the\n# FULL_SIDEBAR option determines if the side bar is limited to only the treeview\n# area (value NO) or if it should extend to the full height of the window (value\n# YES). Setting this to YES gives a layout similar to\n# https://docs.readthedocs.io with more room for contents, but less room for the\n# project logo, title, and description. If either GENERATE_TREEVIEW or\n# DISABLE_INDEX is set to NO, this option has no effect.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFULL_SIDEBAR           = NO\n\n# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that\n# doxygen will group on one line in the generated HTML documentation.\n#\n# Note that a value of 0 will completely suppress the enum values from appearing\n# in the overview section.\n# Minimum value: 0, maximum value: 20, default value: 4.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nENUM_VALUES_PER_LINE   = 4\n\n# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used\n# to set the initial width (in pixels) of the frame in which the tree is shown.\n# Minimum value: 0, maximum value: 1500, default value: 250.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nTREEVIEW_WIDTH         = 250\n\n# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to\n# external symbols imported via tag files in a separate window.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nEXT_LINKS_IN_WINDOW    = NO\n\n# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email\n# addresses.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nOBFUSCATE_EMAILS       = YES\n\n# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg\n# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see\n# https://inkscape.org) to generate formulas as SVG images instead of PNGs for\n# the HTML output. These images will generally look nicer at scaled resolutions.\n# Possible values are: png (the default) and svg (looks nicer but requires the\n# pdf2svg or inkscape tool).\n# The default value is: png.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nHTML_FORMULA_FORMAT    = png\n\n# Use this tag to change the font size of LaTeX formulas included as images in\n# the HTML documentation. When you change the font size after a successful\n# doxygen run you need to manually remove any form_*.png images from the HTML\n# output directory to force them to be regenerated.\n# Minimum value: 8, maximum value: 50, default value: 10.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_FONTSIZE       = 10\n\n# Use the FORMULA_TRANSPARENT tag to determine whether or not the images\n# generated for formulas are transparent PNGs. Transparent PNGs are not\n# supported properly for IE 6.0, but are supported on all modern browsers.\n#\n# Note that when changing this option you need to delete any form_*.png files in\n# the HTML output directory before the changes have effect.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nFORMULA_TRANSPARENT    = YES\n\n# The FORMULA_MACROFILE can contain LaTeX \\newcommand and \\renewcommand commands\n# to create new LaTeX commands to be used in formulas as building blocks. See\n# the section \"Including formulas\" for details.\n\nFORMULA_MACROFILE      =\n\n# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see\n# https://www.mathjax.org) which uses client side JavaScript for the rendering\n# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX\n# installed or if you want to formulas look prettier in the HTML output. When\n# enabled you may also need to install MathJax separately and configure the path\n# to it using the MATHJAX_RELPATH option.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nUSE_MATHJAX            = NO\n\n# With MATHJAX_VERSION it is possible to specify the MathJax version to be used.\n# Note that the different versions of MathJax have different requirements with\n# regards to the different settings, so it is possible that also other MathJax\n# settings have to be changed when switching between the different MathJax\n# versions.\n# Possible values are: MathJax_2 and MathJax_3.\n# The default value is: MathJax_2.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_VERSION        = MathJax_2\n\n# When MathJax is enabled you can set the default output format to be used for\n# the MathJax output. For more details about the output format see MathJax\n# version 2 (see:\n# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3\n# (see:\n# http://docs.mathjax.org/en/latest/web/components/output.html).\n# Possible values are: HTML-CSS (which is slower, but has the best\n# compatibility. This is the name for Mathjax version 2, for MathJax version 3\n# this will be translated into chtml), NativeMML (i.e. MathML. Only supported\n# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This\n# is the name for Mathjax version 3, for MathJax version 2 this will be\n# translated into HTML-CSS) and SVG.\n# The default value is: HTML-CSS.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_FORMAT         = HTML-CSS\n\n# When MathJax is enabled you need to specify the location relative to the HTML\n# output directory using the MATHJAX_RELPATH option. The destination directory\n# should contain the MathJax.js script. For instance, if the mathjax directory\n# is located at the same level as the HTML output directory, then\n# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax\n# Content Delivery Network so you can quickly see the result without installing\n# MathJax. However, it is strongly recommended to install a local copy of\n# MathJax from https://www.mathjax.org before deployment. The default value is:\n# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2\n# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_RELPATH        =\n\n# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax\n# extension names that should be enabled during MathJax rendering. For example\n# for MathJax version 2 (see\n# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions):\n# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols\n# For example for MathJax version 3 (see\n# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html):\n# MATHJAX_EXTENSIONS = ams\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_EXTENSIONS     =\n\n# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces\n# of code that will be used on startup of the MathJax code. See the MathJax site\n# (see:\n# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an\n# example see the documentation.\n# This tag requires that the tag USE_MATHJAX is set to YES.\n\nMATHJAX_CODEFILE       =\n\n# When the SEARCHENGINE tag is enabled doxygen will generate a search box for\n# the HTML output. The underlying search engine uses javascript and DHTML and\n# should work on any modern browser. Note that when using HTML help\n# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)\n# there is already a search function so this one should typically be disabled.\n# For large projects the javascript based search engine can be slow, then\n# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to\n# search using the keyboard; to jump to the search box use <access key> + S\n# (what the <access key> is depends on the OS and browser, but it is typically\n# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down\n# key> to jump into the search results window, the results can be navigated\n# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel\n# the search. The filter options can be selected when the cursor is inside the\n# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>\n# to select a filter and <Enter> or <escape> to activate or cancel the filter\n# option.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_HTML is set to YES.\n\nSEARCHENGINE           = YES\n\n# When the SERVER_BASED_SEARCH tag is enabled the search engine will be\n# implemented using a web server instead of a web client using JavaScript. There\n# are two flavors of web server based searching depending on the EXTERNAL_SEARCH\n# setting. When disabled, doxygen will generate a PHP script for searching and\n# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing\n# and searching needs to be provided by external tools. See the section\n# \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSERVER_BASED_SEARCH    = NO\n\n# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP\n# script for searching. Instead the search results are written to an XML file\n# which needs to be processed by an external indexer. Doxygen will invoke an\n# external search engine pointed to by the SEARCHENGINE_URL option to obtain the\n# search results.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see:\n# https://xapian.org/).\n#\n# See the section \"External Indexing and Searching\" for details.\n# The default value is: NO.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH        = NO\n\n# The SEARCHENGINE_URL should point to a search engine hosted by a web server\n# which will return the search results when EXTERNAL_SEARCH is enabled.\n#\n# Doxygen ships with an example indexer (doxyindexer) and search engine\n# (doxysearch.cgi) which are based on the open source search engine library\n# Xapian (see:\n# https://xapian.org/). See the section \"External Indexing and Searching\" for\n# details.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHENGINE_URL       =\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed\n# search data is written to a file for indexing by an external tool. With the\n# SEARCHDATA_FILE tag the name of this file can be specified.\n# The default file is: searchdata.xml.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nSEARCHDATA_FILE        = searchdata.xml\n\n# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the\n# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is\n# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple\n# projects and redirect the results back to the right project.\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTERNAL_SEARCH_ID     =\n\n# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen\n# projects other than the one defined by this configuration file, but that are\n# all added to the same external search index. Each project needs to have a\n# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of\n# to a relative location where the documentation can be found. The format is:\n# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...\n# This tag requires that the tag SEARCHENGINE is set to YES.\n\nEXTRA_SEARCH_MAPPINGS  =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the LaTeX output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.\n# The default value is: YES.\n\nGENERATE_LATEX         = NO\n\n# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: latex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_OUTPUT           = latex\n\n# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\n# invoked.\n#\n# Note that when not enabling USE_PDFLATEX the default is latex when enabling\n# USE_PDFLATEX the default is pdflatex and when in the later case latex is\n# chosen this is overwritten by pdflatex. For specific output languages the\n# default can have been set differently, this depends on the implementation of\n# the output language.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_CMD_NAME         =\n\n# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate\n# index for LaTeX.\n# Note: This tag is used in the Makefile / make.bat.\n# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file\n# (.tex).\n# The default file is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nMAKEINDEX_CMD_NAME     = makeindex\n\n# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to\n# generate index for LaTeX. In case there is no backslash (\\) as first character\n# it will be automatically added in the LaTeX code.\n# Note: This tag is used in the generated output file (.tex).\n# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.\n# The default value is: makeindex.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_MAKEINDEX_CMD    = makeindex\n\n# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nCOMPACT_LATEX          = NO\n\n# The PAPER_TYPE tag can be used to set the paper type that is used by the\n# printer.\n# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x\n# 14 inches) and executive (7.25 x 10.5 inches).\n# The default value is: a4.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPAPER_TYPE             = a4\n\n# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names\n# that should be included in the LaTeX output. The package can be specified just\n# by its name or with the correct syntax as to be used with the LaTeX\n# \\usepackage command. To get the times font for instance you can specify :\n# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}\n# To use the option intlimits with the amsmath package you can specify:\n# EXTRA_PACKAGES=[intlimits]{amsmath}\n# If left blank no extra packages will be included.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nEXTRA_PACKAGES         =\n\n# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for\n# the generated LaTeX document. The header should contain everything until the\n# first chapter. If it is left blank doxygen will generate a standard header. It\n# is highly recommended to start with a default header using\n# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty\n# and then modify the file new_header.tex. See also section \"Doxygen usage\" for\n# information on how to generate the default header that doxygen normally uses.\n#\n# Note: Only use a user-defined header if you know what you are doing!\n# Note: The header is subject to change so you typically have to regenerate the\n# default header when upgrading to a newer version of doxygen. The following\n# commands have a special meaning inside the header (and footer): For a\n# description of the possible markers and block names see the documentation.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HEADER           =\n\n# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for\n# the generated LaTeX document. The footer should contain everything after the\n# last chapter. If it is left blank doxygen will generate a standard footer. See\n# LATEX_HEADER for more information on how to generate a default footer and what\n# special commands can be used inside the footer. See also section \"Doxygen\n# usage\" for information on how to generate the default footer that doxygen\n# normally uses. Note: Only use a user-defined footer if you know what you are\n# doing!\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_FOOTER           =\n\n# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined\n# LaTeX style sheets that are included after the standard style sheets created\n# by doxygen. Using this option one can overrule certain style aspects. Doxygen\n# will copy the style sheet files to the output directory.\n# Note: The order of the extra style sheet files is of importance (e.g. the last\n# style sheet in the list overrules the setting of the previous ones in the\n# list).\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_STYLESHEET =\n\n# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or\n# other source files which should be copied to the LATEX_OUTPUT output\n# directory. Note that the files will be copied as-is; there are no commands or\n# markers available.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EXTRA_FILES      =\n\n# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is\n# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will\n# contain links (just like the HTML output) instead of page references. This\n# makes the output suitable for online browsing using a PDF viewer.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nPDF_HYPERLINKS         = YES\n\n# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as\n# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX\n# files. Set this option to YES, to get a higher quality PDF documentation.\n#\n# See also section LATEX_CMD_NAME for selecting the engine.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nUSE_PDFLATEX           = YES\n\n# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode\n# command to the generated LaTeX files. This will instruct LaTeX to keep running\n# if errors occur, instead of asking the user for help.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BATCHMODE        = NO\n\n# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the\n# index chapters (such as File Index, Compound Index, etc.) in the output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_HIDE_INDICES     = NO\n\n# The LATEX_BIB_STYLE tag can be used to specify the style to use for the\n# bibliography, e.g. plainnat, or ieeetr. See\n# https://en.wikipedia.org/wiki/BibTeX and \\cite for more info.\n# The default value is: plain.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_BIB_STYLE        = plain\n\n# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated\n# page will contain the date and time when the page was generated. Setting this\n# to NO can help when comparing the output of multiple runs.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_TIMESTAMP        = NO\n\n# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)\n# path from which the emoji images will be read. If a relative path is entered,\n# it will be relative to the LATEX_OUTPUT directory. If left blank the\n# LATEX_OUTPUT directory will be used.\n# This tag requires that the tag GENERATE_LATEX is set to YES.\n\nLATEX_EMOJI_DIRECTORY  =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the RTF output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The\n# RTF output is optimized for Word 97 and may not look too pretty with other RTF\n# readers/editors.\n# The default value is: NO.\n\nGENERATE_RTF           = NO\n\n# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: rtf.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_OUTPUT             = rtf\n\n# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF\n# documents. This may be useful for small projects and may help to save some\n# trees in general.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nCOMPACT_RTF            = NO\n\n# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will\n# contain hyperlink fields. The RTF file will contain links (just like the HTML\n# output) instead of page references. This makes the output suitable for online\n# browsing using Word or some other Word compatible readers that support those\n# fields.\n#\n# Note: WordPad (write) and others do not support links.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_HYPERLINKS         = NO\n\n# Load stylesheet definitions from file. Syntax is similar to doxygen's\n# configuration file, i.e. a series of assignments. You only have to provide\n# replacements, missing definitions are set to their default value.\n#\n# See also section \"Doxygen usage\" for information on how to generate the\n# default style sheet that doxygen normally uses.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_STYLESHEET_FILE    =\n\n# Set optional variables used in the generation of an RTF document. Syntax is\n# similar to doxygen's configuration file. A template extensions file can be\n# generated using doxygen -e rtf extensionFile.\n# This tag requires that the tag GENERATE_RTF is set to YES.\n\nRTF_EXTENSIONS_FILE    =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the man page output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for\n# classes and files.\n# The default value is: NO.\n\nGENERATE_MAN           = NO\n\n# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it. A directory man3 will be created inside the directory specified by\n# MAN_OUTPUT.\n# The default directory is: man.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_OUTPUT             = man\n\n# The MAN_EXTENSION tag determines the extension that is added to the generated\n# man pages. In case the manual section does not start with a number, the number\n# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is\n# optional.\n# The default value is: .3.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_EXTENSION          = .3\n\n# The MAN_SUBDIR tag determines the name of the directory created within\n# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by\n# MAN_EXTENSION with the initial . removed.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_SUBDIR             =\n\n# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it\n# will generate one additional man file for each entity documented in the real\n# man page(s). These additional files only source the real man page, but without\n# them the man command would be unable to find the correct page.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_MAN is set to YES.\n\nMAN_LINKS              = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the XML output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that\n# captures the structure of the code including all documentation.\n# The default value is: NO.\n\nGENERATE_XML           = NO\n\n# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a\n# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of\n# it.\n# The default directory is: xml.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_OUTPUT             = xml\n\n# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program\n# listings (including syntax highlighting and cross-referencing information) to\n# the XML output. Note that enabling this will significantly increase the size\n# of the XML output.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_PROGRAMLISTING     = YES\n\n# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include\n# namespace members in file scope as well, matching the HTML output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_XML is set to YES.\n\nXML_NS_MEMB_FILE_SCOPE = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the DOCBOOK output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files\n# that can be used to generate PDF.\n# The default value is: NO.\n\nGENERATE_DOCBOOK       = NO\n\n# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.\n# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in\n# front of it.\n# The default directory is: docbook.\n# This tag requires that the tag GENERATE_DOCBOOK is set to YES.\n\nDOCBOOK_OUTPUT         = docbook\n\n#---------------------------------------------------------------------------\n# Configuration options for the AutoGen Definitions output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an\n# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures\n# the structure of the code including all documentation. Note that this feature\n# is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_AUTOGEN_DEF   = NO\n\n#---------------------------------------------------------------------------\n# Configuration options related to the Perl module output\n#---------------------------------------------------------------------------\n\n# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module\n# file that captures the structure of the code including all documentation.\n#\n# Note that this feature is still experimental and incomplete at the moment.\n# The default value is: NO.\n\nGENERATE_PERLMOD       = NO\n\n# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary\n# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI\n# output from the Perl module output.\n# The default value is: NO.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_LATEX          = NO\n\n# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely\n# formatted so it can be parsed by a human reader. This is useful if you want to\n# understand what is going on. On the other hand, if this tag is set to NO, the\n# size of the Perl module output will be much smaller and Perl will parse it\n# just the same.\n# The default value is: YES.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_PRETTY         = YES\n\n# The names of the make variables in the generated doxyrules.make file are\n# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful\n# so different doxyrules.make files included by the same Makefile don't\n# overwrite each other's variables.\n# This tag requires that the tag GENERATE_PERLMOD is set to YES.\n\nPERLMOD_MAKEVAR_PREFIX =\n\n#---------------------------------------------------------------------------\n# Configuration options related to the preprocessor\n#---------------------------------------------------------------------------\n\n# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all\n# C-preprocessor directives found in the sources and include files.\n# The default value is: YES.\n\nENABLE_PREPROCESSING   = YES\n\n# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names\n# in the source code. If set to NO, only conditional compilation will be\n# performed. Macro expansion can be done in a controlled way by setting\n# EXPAND_ONLY_PREDEF to YES.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nMACRO_EXPANSION        = NO\n\n# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then\n# the macro expansion is limited to the macros specified with the PREDEFINED and\n# EXPAND_AS_DEFINED tags.\n# The default value is: NO.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_ONLY_PREDEF     = NO\n\n# If the SEARCH_INCLUDES tag is set to YES, the include files in the\n# INCLUDE_PATH will be searched if a #include is found.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSEARCH_INCLUDES        = YES\n\n# The INCLUDE_PATH tag can be used to specify one or more directories that\n# contain include files that are not input files but should be processed by the\n# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of\n# RECURSIVE has no effect here.\n# This tag requires that the tag SEARCH_INCLUDES is set to YES.\n\nINCLUDE_PATH           =\n\n# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\n# patterns (like *.h and *.hpp) to filter out the header-files in the\n# directories. If left blank, the patterns specified with FILE_PATTERNS will be\n# used.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nINCLUDE_FILE_PATTERNS  =\n\n# The PREDEFINED tag can be used to specify one or more macro names that are\n# defined before the preprocessor is started (similar to the -D option of e.g.\n# gcc). The argument of the tag is a list of macros of the form: name or\n# name=definition (no spaces). If the definition and the \"=\" are omitted, \"=1\"\n# is assumed. To prevent a macro definition from being undefined via #undef or\n# recursively expanded use the := operator instead of the = operator.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nPREDEFINED             =\n\n# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this\n# tag can be used to specify a list of macro names that should be expanded. The\n# macro definition that is found in the sources will be used. Use the PREDEFINED\n# tag if you want to use a different macro definition that overrules the\n# definition found in the source code.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nEXPAND_AS_DEFINED      =\n\n# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will\n# remove all references to function-like macros that are alone on a line, have\n# an all uppercase name, and do not end with a semicolon. Such function macros\n# are typically used for boiler-plate code, and will confuse the parser if not\n# removed.\n# The default value is: YES.\n# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.\n\nSKIP_FUNCTION_MACROS   = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to external references\n#---------------------------------------------------------------------------\n\n# The TAGFILES tag can be used to specify one or more tag files. For each tag\n# file the location of the external documentation should be added. The format of\n# a tag file without this location is as follows:\n# TAGFILES = file1 file2 ...\n# Adding location for the tag files is done as follows:\n# TAGFILES = file1=loc1 \"file2 = loc2\" ...\n# where loc1 and loc2 can be relative or absolute paths or URLs. See the\n# section \"Linking to external documentation\" for more information about the use\n# of tag files.\n# Note: Each tag file must have a unique name (where the name does NOT include\n# the path). If a tag file is not located in the directory in which doxygen is\n# run, you must also specify the path to the tagfile here.\n\nTAGFILES               =\n\n# When a file name is specified after GENERATE_TAGFILE, doxygen will create a\n# tag file that is based on the input files it reads. See section \"Linking to\n# external documentation\" for more information about the usage of tag files.\n\nGENERATE_TAGFILE       =\n\n# If the ALLEXTERNALS tag is set to YES, all external class will be listed in\n# the class index. If set to NO, only the inherited external classes will be\n# listed.\n# The default value is: NO.\n\nALLEXTERNALS           = NO\n\n# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed\n# in the modules index. If set to NO, only the current project's groups will be\n# listed.\n# The default value is: YES.\n\nEXTERNAL_GROUPS        = YES\n\n# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in\n# the related pages index. If set to NO, only the current project's pages will\n# be listed.\n# The default value is: YES.\n\nEXTERNAL_PAGES         = YES\n\n#---------------------------------------------------------------------------\n# Configuration options related to the dot tool\n#---------------------------------------------------------------------------\n\n# You can include diagrams made with dia in doxygen documentation. Doxygen will\n# then run dia to produce the diagram and insert it in the documentation. The\n# DIA_PATH tag allows you to specify the directory where the dia binary resides.\n# If left empty dia is assumed to be found in the default search path.\n\nDIA_PATH               =\n\n# If set to YES the inheritance and collaboration graphs will hide inheritance\n# and usage relations if the target is undocumented or is not a class.\n# The default value is: YES.\n\nHIDE_UNDOC_RELATIONS   = YES\n\n# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is\n# available from the path. This tool is part of Graphviz (see:\n# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent\n# Bell Labs. The other options in this section have no effect if this option is\n# set to NO\n# The default value is: YES.\n\nHAVE_DOT               = YES\n\n# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed\n# to run in parallel. When set to 0 doxygen will base this on the number of\n# processors available in the system. You can set it explicitly to a value\n# larger than 0 to get control over the balance between CPU load and processing\n# speed.\n# Minimum value: 0, maximum value: 32, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_NUM_THREADS        = 0\n\n# When you want a differently looking font in the dot files that doxygen\n# generates you can specify the font name using DOT_FONTNAME. You need to make\n# sure dot is able to find the font, which can be done by putting it in a\n# standard location or by setting the DOTFONTPATH environment variable or by\n# setting DOT_FONTPATH to the directory containing the font.\n# The default value is: Helvetica.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTNAME           = Helvetica\n\n# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of\n# dot graphs.\n# Minimum value: 4, maximum value: 24, default value: 10.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTSIZE           = 10\n\n# By default doxygen will tell dot to use the default font as specified with\n# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set\n# the path where dot can find it using this tag.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_FONTPATH           =\n\n# If the CLASS_GRAPH tag is set to YES (or GRAPH) then doxygen will generate a\n# graph for each documented class showing the direct and indirect inheritance\n# relations. In case HAVE_DOT is set as well dot will be used to draw the graph,\n# otherwise the built-in generator will be used. If the CLASS_GRAPH tag is set\n# to TEXT the direct and indirect inheritance relations will be shown as texts /\n# links.\n# Possible values are: NO, YES, TEXT and GRAPH.\n# The default value is: YES.\n\nCLASS_GRAPH            = YES\n\n# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a\n# graph for each documented class showing the direct and indirect implementation\n# dependencies (inheritance, containment, and class references variables) of the\n# class with other documented classes.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCOLLABORATION_GRAPH    = YES\n\n# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for\n# groups, showing the direct groups dependencies. See also the chapter Grouping\n# in the manual.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGROUP_GRAPHS           = YES\n\n# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and\n# collaboration diagrams in a style similar to the OMG's Unified Modeling\n# Language.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nUML_LOOK               = NO\n\n# If the UML_LOOK tag is enabled, the fields and methods are shown inside the\n# class node. If there are many fields or methods and many nodes the graph may\n# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the\n# number of items for each type to make the size more manageable. Set this to 0\n# for no limit. Note that the threshold may be exceeded by 50% before the limit\n# is enforced. So when you set the threshold to 10, up to 15 fields may appear,\n# but if the number exceeds 15, the total amount of fields shown is limited to\n# 10.\n# Minimum value: 0, maximum value: 100, default value: 10.\n# This tag requires that the tag UML_LOOK is set to YES.\n\nUML_LIMIT_NUM_FIELDS   = 10\n\n# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and\n# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS\n# tag is set to YES, doxygen will add type and arguments for attributes and\n# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen\n# will not generate fields with class member information in the UML graphs. The\n# class diagrams will look similar to the default class diagrams but using UML\n# notation for the relationships.\n# Possible values are: NO, YES and NONE.\n# The default value is: NO.\n# This tag requires that the tag UML_LOOK is set to YES.\n\nDOT_UML_DETAILS        = NO\n\n# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters\n# to display on a single line. If the actual line length exceeds this threshold\n# significantly it will wrapped across multiple lines. Some heuristics are apply\n# to avoid ugly line breaks.\n# Minimum value: 0, maximum value: 1000, default value: 17.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_WRAP_THRESHOLD     = 17\n\n# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and\n# collaboration graphs will show the relations between templates and their\n# instances.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nTEMPLATE_RELATIONS     = NO\n\n# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to\n# YES then doxygen will generate a graph for each documented file showing the\n# direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDE_GRAPH          = YES\n\n# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are\n# set to YES then doxygen will generate a graph for each documented file showing\n# the direct and indirect include dependencies of the file with other documented\n# files.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINCLUDED_BY_GRAPH      = YES\n\n# If the CALL_GRAPH tag is set to YES then doxygen will generate a call\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable call graphs for selected\n# functions only using the \\callgraph command. Disabling a call graph can be\n# accomplished by means of the command \\hidecallgraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALL_GRAPH             = NO\n\n# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller\n# dependency graph for every global function or class method.\n#\n# Note that enabling this option will significantly increase the time of a run.\n# So in most cases it will be better to enable caller graphs for selected\n# functions only using the \\callergraph command. Disabling a caller graph can be\n# accomplished by means of the command \\hidecallergraph.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nCALLER_GRAPH           = NO\n\n# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical\n# hierarchy of all classes instead of a textual one.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGRAPHICAL_HIERARCHY    = YES\n\n# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the\n# dependencies a directory has on other directories in a graphical way. The\n# dependency relations are determined by the #include relations between the\n# files in the directories.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDIRECTORY_GRAPH        = YES\n\n# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels\n# of child directories generated in directory dependency graphs by dot.\n# Minimum value: 1, maximum value: 25, default value: 1.\n# This tag requires that the tag DIRECTORY_GRAPH is set to YES.\n\nDIR_GRAPH_MAX_DEPTH    = 1\n\n# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\n# generated by dot. For an explanation of the image formats see the section\n# output formats in the documentation of the dot tool (Graphviz (see:\n# http://www.graphviz.org/)).\n# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order\n# to make the SVG files visible in IE 9+ (other browsers do not have this\n# requirement).\n# Possible values are: png, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd,\n# gif, gif:cairo, gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd,\n# png:cairo, png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and\n# png:gdiplus:gdiplus.\n# The default value is: png.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_IMAGE_FORMAT       = png\n\n# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to\n# enable generation of interactive SVG images that allow zooming and panning.\n#\n# Note that this requires a modern browser other than Internet Explorer. Tested\n# and working are Firefox, Chrome, Safari, and Opera.\n# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make\n# the SVG files visible. Older versions of IE do not have SVG support.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nINTERACTIVE_SVG        = NO\n\n# The DOT_PATH tag can be used to specify the path where the dot tool can be\n# found. If left blank, it is assumed the dot tool can be found in the path.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_PATH               =\n\n# The DOTFILE_DIRS tag can be used to specify one or more directories that\n# contain dot files that are included in the documentation (see the \\dotfile\n# command).\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOTFILE_DIRS           =\n\n# The MSCFILE_DIRS tag can be used to specify one or more directories that\n# contain msc files that are included in the documentation (see the \\mscfile\n# command).\n\nMSCFILE_DIRS           =\n\n# The DIAFILE_DIRS tag can be used to specify one or more directories that\n# contain dia files that are included in the documentation (see the \\diafile\n# command).\n\nDIAFILE_DIRS           =\n\n# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the\n# path where java can find the plantuml.jar file or to the filename of jar file\n# to be used. If left blank, it is assumed PlantUML is not used or called during\n# a preprocessing step. Doxygen will generate a warning when it encounters a\n# \\startuml command in this case and will not generate output for the diagram.\n\nPLANTUML_JAR_PATH      =\n\n# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a\n# configuration file for plantuml.\n\nPLANTUML_CFG_FILE      =\n\n# When using plantuml, the specified paths are searched for files specified by\n# the !include statement in a plantuml block.\n\nPLANTUML_INCLUDE_PATH  =\n\n# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes\n# that will be shown in the graph. If the number of nodes in a graph becomes\n# larger than this value, doxygen will truncate the graph, which is visualized\n# by representing a node as a red box. Note that doxygen if the number of direct\n# children of the root node in a graph is already larger than\n# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that\n# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.\n# Minimum value: 0, maximum value: 10000, default value: 50.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_GRAPH_MAX_NODES    = 50\n\n# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs\n# generated by dot. A depth value of 3 means that only nodes reachable from the\n# root by following a path via at most 3 edges will be shown. Nodes that lay\n# further from the root node will be omitted. Note that setting this option to 1\n# or 2 may greatly reduce the computation time needed for large code bases. Also\n# note that the size of a graph can be further restricted by\n# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.\n# Minimum value: 0, maximum value: 1000, default value: 0.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nMAX_DOT_GRAPH_DEPTH    = 0\n\n# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent\n# background. This is disabled by default, because dot on Windows does not seem\n# to support this out of the box.\n#\n# Warning: Depending on the platform used, enabling this option may lead to\n# badly anti-aliased labels on the edges of a graph (i.e. they become hard to\n# read).\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_TRANSPARENT        = NO\n\n# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output\n# files in one run (i.e. multiple -o and -T options on the command line). This\n# makes dot run faster, but since only newer versions of dot (>1.8.10) support\n# this, this feature is disabled by default.\n# The default value is: NO.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nDOT_MULTI_TARGETS      = NO\n\n# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page\n# explaining the meaning of the various boxes and arrows in the dot generated\n# graphs.\n# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal\n# graphical representation for inheritance and collaboration diagrams is used.\n# The default value is: YES.\n# This tag requires that the tag HAVE_DOT is set to YES.\n\nGENERATE_LEGEND        = YES\n\n# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate\n# files that are used to generate the various graphs.\n#\n# Note: This setting is not only used for dot files but also for msc temporary\n# files.\n# The default value is: YES.\n\nDOT_CLEANUP            = YES\n"
  },
  {
    "path": ".editorconfig",
    "content": "# EditorConfig: https://EditorConfig.org\n\nroot = true\n\n[*]\nindent_style = space\ncharset = utf-8\nend_of_line = lf\nindent_size = 4\ninsert_final_newline = true\ntrim_trailing_whitespace = true\n\n[**.{json,yml}]\nindent_size = 2\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Github language settings\n*.h linguist-language=c\n*.c linguist-language=c\n\n*.h text eol=auto\n*.c text eol=auto\n"
  },
  {
    "path": ".github/ci_compile_sources.sh",
    "content": "#!/bin/sh\n# This shellscript compiles each Nuklear/src/*.c source separetly\n# in order to check for simple compilation failures by our CI runner.\n\n# FIXME: This script compiles WITHOUT LINKING, which means that it won't catch\n# any potential failures at link time. We don't have any example and/or demo\n# that would work without amalgamated header, so we can't really test linking\n# at the moment (but we defenetily should do this in the future!)\n\n# FIXME: This script currently lives in Nuklear/.github/* folder because\n# there are no other scripts like this one, and having it somewhere else\n# could confuse people. Same reason why it wasn't made as Makefile.\n\nset -e\n\nCC=cc\nSRCDIR=./src\n\nset -- \"\"\nset -- \"$@\" -std=c89\nset -- \"$@\" -Wall\nset -- \"$@\" -Wextra\nset -- \"$@\" -pedantic\nCFLAGS=$*\n\nset -- \"\"\nset -- \"$@\" -DNK_INCLUDE_FIXED_TYPES\nset -- \"$@\" -DNK_INCLUDE_DEFAULT_ALLOCATOR\nset -- \"$@\" -DNK_INCLUDE_STANDARD_IO\nset -- \"$@\" -DNK_INCLUDE_STANDARD_VARARGS\nset -- \"$@\" -DNK_INCLUDE_STANDARD_BOOL\nset -- \"$@\" -DNK_INCLUDE_VERTEX_BUFFER_OUTPUT\nset -- \"$@\" -DNK_INCLUDE_DEFAULT_FONT\nset -- \"$@\" -DNK_INCLUDE_COMMAND_USERDATA\nCPPFLAGS=$*\n\nretcode=0\n\nfor i in \"${SRCDIR}\"/*.c ; do\n    printf \"CC %s\\n\" \"${i}\"\n    # shellcheck disable=SC2086\n    if ! $CC -x c -c \"${i}\" -o /dev/null $CFLAGS $CPPFLAGS ; then\n        retcode=1\n    fi\ndone\n\nexit \"${retcode}\"\n\n"
  },
  {
    "path": ".github/workflows/ccpp.yml",
    "content": "name: C/C++ CI\n\non: [push, pull_request]\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v4\n    - name: apt-update\n      run: sudo apt-get update -qq\n    - name: apt get demo-libs\n      run: sudo apt-get install -y --no-install-recommends glslc liballegro5-dev liballegro-image5-dev liballegro-ttf5-dev libcairo2-dev libglfw3 libglfw3-dev libglew-dev libsdl2-dev libvulkan-dev libwayland-dev libx11-dev libxcb1-dev libxcb-util0-dev libxcb-keysyms1-dev libxft-dev libxkbcommon-x11-dev wayland-protocols\n    - name: build allegro5\n      run: make -C demo/allegro5\n    - name: build glfw_opengl2\n      run: make -C demo/glfw_opengl2\n    - name: build glfw_opengl3\n      run: make -C demo/glfw_opengl3\n    - name: build glfw_opengl4\n      run: make -C demo/glfw_opengl4\n    - name: build glfw_vulkan\n      run: make -C demo/glfw_vulkan\n    - name: build sdl_opengl2\n      run: make -C demo/sdl_opengl2\n    - name: build sdl_opengl3\n      run: make -C demo/sdl_opengl3\n    - name: build sdl_opengles2\n      run: make -C demo/sdl_opengles2\n    - name: build sdl_renderer\n      run: make -C demo/sdl_renderer\n    - name: build sdl_vulkan\n      run: make -C demo/sdl_vulkan\n    - name: build sdl_rawfb\n      run: make -C demo/rawfb/sdl\n    - name: build wayland_rawfb\n      run: make -C demo/rawfb/wayland\n    - name: build x11\n      run: make -C demo/x11\n    - name: build x11_opengl2\n      run: make -C demo/x11_opengl2\n    - name: build x11_opengl3\n      run: make -C demo/x11_opengl3\n    - name: build x11_rawfb\n      run: make -C demo/rawfb/x11\n    - name: build xcb_cairo\n      run: make -C demo/xcb_cairo\n    - name: build example\n      run: make -C example\n    - name: compile sources\n      run: sh -e ./.github/ci_compile_sources.sh\n"
  },
  {
    "path": ".github/workflows/create-tag.yml",
    "content": "name: Create Tag\n\non:\n  push:\n    branches:\n      - master\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n    - uses: actions/checkout@v4\n    - uses: butlerlogic/action-autotag@1.1.2\n      env:\n        GITHUB_TOKEN: \"${{ secrets.GITHUB_TOKEN }}\"\n      with:\n        root: clib.json\n"
  },
  {
    "path": ".github/workflows/docs.yml",
    "content": "name: Documentation on github.io\n\non:\n  push:\n    branches: [ master ]\n\njobs:\n  build-documentation:\n    runs-on: ubuntu-latest\n    steps:\n    - name: checkout\n      uses: actions/checkout@v4\n    - name: apt-update\n      run: sudo apt-get update -qq\n    - name: apt-get doxygen\n      run: sudo apt-get install -y doxygen\n    - name: build doc\n      run: make docs\n    - name: deploy\n      uses: peaceiris/actions-gh-pages@v4\n      with:\n        github_token: ${{ secrets.GITHUB_TOKEN }}\n        publish_dir: ./doc/html/\n        enable_jekyll: false\n        allow_empty_commit: false\n        force_orphan: true\n"
  },
  {
    "path": ".gitignore",
    "content": "demo/*/*/demo\ndemo/*/bin/*\nexample/bin/*\n/doc\n*.tmp\n*.swo\n*.swp\n*.o\n*.obj\n*.exe\n*.dSYM\n/private/\n"
  },
  {
    "path": "LICENSE",
    "content": "------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Micha Mettke\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n-----------------------------------------------------------------------------\n"
  },
  {
    "path": "Makefile",
    "content": "\n######################################################################################\n##  \t\t\t\t\t\t\t\t SETTINGS                                       ##\n######################################################################################\n\n## path stuff\nDOCS_PATH:=./doc\nDEMO_PATH=demo\nSRC_PATH=src\n\n\n## Documents settings\nDOXYFILE:=.Doxyfile\n\n\n## HEADER file packing settings\n## note: source file paths are prefixed later, no need to add prefix here; just\n## give it the name.\nMACRO = NK\nINTRO =  HEADER.md\nPUB = nuklear.h\nOUTPUT = nuklear.h\n\nPRIV1 = nuklear_internal.h nuklear_math.c nuklear_util.c nuklear_color.c nuklear_utf8.c nuklear_buffer.c nuklear_string.c nuklear_draw.c nuklear_vertex.c \n\nEXTERN =  stb_rect_pack.h stb_truetype.h \n\nPRIV2 = nuklear_font.c nuklear_input.c nuklear_style.c nuklear_context.c nuklear_pool.c nuklear_page_element.c nuklear_table.c nuklear_panel.c nuklear_window.c nuklear_popup.c nuklear_contextual.c nuklear_menu.c nuklear_layout.c nuklear_tree.c nuklear_group.c nuklear_list_view.c nuklear_widget.c nuklear_text.c nuklear_image.c nuklear_9slice.c nuklear_button.c nuklear_toggle.c nuklear_selectable.c nuklear_slider.c nuklear_knob.c nuklear_progress.c nuklear_scrollbar.c nuklear_text_editor.c nuklear_edit.c nuklear_property.c nuklear_chart.c nuklear_color_picker.c nuklear_combo.c nuklear_tooltip.c\n\nOUTRO = LICENSE CHANGELOG CREDITS\n\n## Demo settings\nDEMO_LIST = $(shell find $(DEMO_PATH) -type f -name Makefile -printf \"%h \")\n\n######################################################################################\n##  \t\t\t\t\t\t\t\t RECIPES                                        ##\n######################################################################################\n\n\n.PHONY: usage all demos $(DEMO_LIST)\n\nusage:\n\techo \"make docs\t\tto create documentation\"\n\techo \"make nuke\t\tto rebuild the single header nuklear.h from source\"\n\techo \"make demos\tto build all of the demos\"\n\techo \"make all \t\tto re-pack the header and create documentation\"\n\nall: docs nuke demos \ndemos: $(DEMO_LIST)\n\n\n########################################################################################\n##   Nuklear.h\n\nnuke: $(addprefix $(SRC_PATH)/, $(SRC))\n\tpython3 $(SRC_PATH)/build.py --macro $(MACRO) --intro $(addprefix $(SRC_PATH)/, $(INTRO)) --pub $(addprefix $(SRC_PATH)/, $(PUB)) --priv1 \"$(addprefix $(SRC_PATH)/, $(PRIV1))\" --extern \"$(addprefix $(SRC_PATH)/, $(EXTERN))\" --priv2 \"$(addprefix $(SRC_PATH)/, $(PRIV2))\" --outro \"$(addprefix $(SRC_PATH)/, $(OUTRO))\" > $(OUTPUT)\n\n\n\n\n\n########################################################################################\n##   Docs\n\ndocs: $(DOCS_PATH)/html/index.html \n\n$(DOCS_PATH)/html/index.html: $(DOCS_PATH)/doxygen-awesome-css/doxygen-awesome.css $(DOXYFILE)\n\tdoxygen $(DOXYFILE)\n\n$(DOXYFILE):\n\tdoxygen -g $@\n\n$(DOCS_PATH)/doxygen-awesome-css/doxygen-awesome.css:\n\tgit clone https://github.com/jothepro/doxygen-awesome-css.git $(DOCS_PATH)/doxygen-awesome-css --branch v2.3.4\n\n\n\n########################################################################################\n##   Demos\n\n$(DEMO_LIST):\n\t$(MAKE) -C $@\n\n\n\n########################################################################################\n##   Utility helpers\n\nclean:\n\trm -rf $(DOCS_PATH)/html $(OUTPUT)\n"
  },
  {
    "path": "Readme.md",
    "content": "# Nuklear\n\n[![](https://github.com/Immediate-Mode-UI/Nuklear/workflows/C%2FC++%20CI/badge.svg )](https://github.com/Immediate-Mode-UI/Nuklear/actions)\n\nThis is a minimal-state, immediate-mode graphical user interface toolkit\nwritten in ANSI C and licensed under public domain. It was designed as a simple\nembeddable user interface for application and does not have any dependencies,\na default render backend or OS window/input handling but instead provides a\nhighly modular, library-based approach, with simple input state for input and\ndraw commands describing primitive shapes as output. So instead of providing a\nlayered library that tries to abstract over a number of platform and\nrender backends, it focuses only on the actual UI.\n\n## Features\n\n- Immediate-mode graphical user interface toolkit\n- Single-header library\n- Written in C89 (ANSI C)\n- Small codebase (~18kLOC)\n- Focus on portability, efficiency and simplicity\n- No dependencies (not even the standard library if not wanted)\n- Fully skinnable and customizable\n- Low memory footprint with total control of memory usage if needed / wanted\n- UTF-8 support\n- No global or hidden state\n- Customizable library modules (you can compile and use only what you need)\n- Optional font baker and vertex buffer output\n- [Documentation](https://Immediate-Mode-UI.github.io/Nuklear/)\n\n## Building\n\nThis library is self-contained in one single header file and can be used either\nin header-only mode or in implementation mode. The header-only mode is used\nby default when included and allows including this header in other headers\nand does not contain the actual implementation.\n\nThe implementation mode requires defining the preprocessor macro\n`NK_IMPLEMENTATION` in *one* .c/.cpp file before `#include`ing this file, e.g.:\n```c\n#define NK_IMPLEMENTATION\n#include \"nuklear.h\"\n```\nIMPORTANT: Every time you include \"nuklear.h\" you have to define the same optional flags.\nThis is very important; not doing it either leads to compiler errors, or even worse, stack corruptions.\n\n## Gallery\n\n![screenshot](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)\n![screen](https://cloud.githubusercontent.com/assets/8057201/13538240/acd96876-e249-11e5-9547-5ac0b19667a0.png)\n![screen2](https://cloud.githubusercontent.com/assets/8057201/13538243/b04acd4c-e249-11e5-8fd2-ad7744a5b446.png)\n![node](https://cloud.githubusercontent.com/assets/8057201/9976995/e81ac04a-5ef7-11e5-872b-acd54fbeee03.gif)\n![skinning](https://cloud.githubusercontent.com/assets/8057201/15991632/76494854-30b8-11e6-9555-a69840d0d50b.png)\n![gamepad](https://cloud.githubusercontent.com/assets/8057201/14902576/339926a8-0d9c-11e6-9fee-a8b73af04473.png)\n\n## Example\n\n```c\n/* init gui state */\nstruct nk_context ctx;\nnk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);\n\nenum {EASY, HARD};\nstatic int op = EASY;\nstatic float value = 0.6f;\nstatic int i =  20;\n\nif (nk_begin(&ctx, \"Show\", nk_rect(50, 50, 220, 220),\n    NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) {\n    /* fixed widget pixel width */\n    nk_layout_row_static(&ctx, 30, 80, 1);\n    if (nk_button_label(&ctx, \"button\")) {\n        /* event handling */\n    }\n\n    /* fixed widget window ratio width */\n    nk_layout_row_dynamic(&ctx, 30, 2);\n    if (nk_option_label(&ctx, \"easy\", op == EASY)) op = EASY;\n    if (nk_option_label(&ctx, \"hard\", op == HARD)) op = HARD;\n\n    /* custom widget pixel width */\n    nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);\n    {\n        nk_layout_row_push(&ctx, 50);\n        nk_label(&ctx, \"Volume:\", NK_TEXT_LEFT);\n        nk_layout_row_push(&ctx, 110);\n        nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);\n    }\n    nk_layout_row_end(&ctx);\n}\nnk_end(&ctx);\n```\n![example](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)\n\n## Bindings\nThere are a number of nuklear bindings for different languages created by other authors.\nI cannot attest for their quality since I am not necessarily proficient in any of these\nlanguages. Furthermore there are no guarantee that all bindings will always be kept up to date:\n\n- [Java](https://github.com/glegris/nuklear4j) by Guillaume Legris\n- [D](https://github.com/Timu5/bindbc-nuklear) by Mateusz Muszyński\n- [Golang](https://github.com/golang-ui/nuklear) by golang-ui@github.com\n- [Rust](https://github.com/snuk182/nuklear-rust) by snuk182@github.com\n- [Chicken](https://github.com/wasamasa/nuklear) by wasamasa@github.com\n- [Nim](https://github.com/zacharycarter/nuklear-nim) by zacharycarter@github.com\n- Lua\n  - [LÖVE-Nuklear](https://github.com/keharriso/love-nuklear) by Kevin Harrison\n  - [MoonNuklear](https://github.com/stetre/moonnuklear) by Stefano Trettel\n- Python\n  - [pyNuklear](https://github.com/billsix/pyNuklear) by William Emerison Six (ctypes-based wrapper)\n  - [pynk](https://github.com/nathanrw/nuklear-cffi) by nathanrw@github.com (cffi binding)\n- [CSharp/.NET](https://github.com/cartman300/NuklearDotNet) by cartman300@github.com\n- [V](https://github.com/nsauzede/vnk) by Nicolas Sauzede\n\n## Credits\nDeveloped by Micha Mettke and every direct or indirect contributor to the GitHub.\n\n\nEmbeds `stb_texedit`, `stb_truetype` and `stb_rectpack` by Sean Barrett (public domain)\nEmbeds `ProggyClean.ttf` font by Tristan Grimmer (MIT license).\n\n\nBig thank you to Omar Cornut (ocornut@github) for his [imgui](https://github.com/ocornut/imgui) library and\ngiving me the inspiration for this library, Casey Muratori for handmade hero\nand his original immediate-mode graphical user interface idea and Sean\nBarrett for his amazing single-header [libraries](https://github.com/nothings/stb) which restored my faith\nin libraries and brought me to create some of my own. Finally Apoorva Joshi for his single-header [file packer](http://apoorvaj.io/single-header-packer.html).\n\n## License\nNuklear is avaliable under either the MIT License or public domain.\nSee [LICENSE](LICENSE) for more info.\n\n## Reviewers guide\n\nWhen reviewing pull request there are common things a reviewer should keep\nin mind.\n\nReviewing changes to `src/*` and `nuklear.h`:\n\n* Ensure C89 compatibility.\n* The code should work for several backends to an acceptable degree.\n* Check no other parts of `nuklear.h` are related to the PR and thus nothing is missing.\n* Recommend simple optimizations.\n  * Pass small structs by value instead of by pointer.\n  * Use local buffers over heap allocation when possible.\n* Check that the coding style is consistent with code around it.\n  * Variable/function name casing.\n  * Indentation.\n  * Curly bracket (`{}`) placement.\n* Ensure that the contributor has bumped the appropriate version in\n  [clib.json](https://github.com/Immediate-Mode-UI/Nuklear/blob/master/clib.json)\n  and added their changes to the\n  [CHANGELOG](https://github.com/Immediate-Mode-UI/Nuklear/blob/master/src/CHANGELOG).\n* Have at least one other person review the changes before merging.\n\nReviewing changes to `demo/*`, `example/*` and other files in the repo:\n\n* Focus on getting working code merged.\n  * We want to make it easy for people to get started with Nuklear, and any\n    `demo` and `example` improvements helps in this regard.\n* Use of newer C features, or even other languages is not discouraged.\n  * If another language is used, ensure that the build process is easy to figure out.\n* Messy or less efficient code can be merged so long as these outliers are pointed out\n  and easy to find.\n* Version shouldn't be bumped for these changes.\n* Changes that improves code to be more inline with `nuklear.h` are ofc always welcome.\n\n"
  },
  {
    "path": "clib.json",
    "content": "{\n  \"name\": \"nuklear\",\n  \"version\": \"4.13.2\",\n  \"repo\": \"Immediate-Mode-UI/Nuklear\",\n  \"description\": \"A small ANSI C gui toolkit\",\n  \"keywords\": [\"gl\", \"ui\", \"toolkit\"],\n  \"license\": \"MIT, Unlicense\",\n  \"src\": [\"nuklear.h\"]\n}\n"
  },
  {
    "path": "demo/allegro5/KeyboardHandleriOS.h",
    "content": "#import <UIKit/UIKit.h>\n\n#include <allegro5/allegro.h>\n\n@interface KeyboardHandleriOS : UIView <UIKeyInput>\n-(void)setCustomKeyboardEventSource:(ALLEGRO_EVENT_SOURCE*)ev_src;\n-(void)show;\n-(void)hide;\n@end\n\n"
  },
  {
    "path": "demo/allegro5/KeyboardHandleriOS.m",
    "content": "#ifdef __OBJC__\n#import <UIKit/UIKit.h>\n#endif\n#import \"KeyboardHandleriOS.h\"\n#include <allegro5/allegro.h>\n#include <allegro5/allegro_iphone_objc.h>\n@interface KeyboardHandleriOS()\n{\n    ALLEGRO_EVENT_SOURCE *event_source;\n    ALLEGRO_DISPLAY *current_display;\n}\n@end\n@implementation KeyboardHandleriOS\n- (id)init {\n    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];\n    self = [self initWithFrame:CGRectMake(-100, -100, 0, 0)];\n    event_source = NULL;\n    current_display = al_get_current_display();\n    UIView* v = al_iphone_get_view(current_display);\n    [v addSubview:self];\n    return self;\n}\n\n- (void)setCustomKeyboardEventSource:(ALLEGRO_EVENT_SOURCE *)ev_src {\n    event_source = ev_src;\n}\n\n- (UIKeyboardType) keyboardType\n{\n    return UIKeyboardTypeASCIICapable;\n}\n\n- (UITextAutocorrectionType) autocorrectionType\n{\n    return UITextAutocorrectionTypeNo;\n}\n\n-(BOOL)canBecomeFirstResponder {\n    return YES;\n}\n\n- (void)deleteBackward {\n    \n    if (!event_source) {\n        NSLog(@\"deleteBackward(): No event source found, not sending events\");\n        return;\n    }\n    \n    ALLEGRO_EVENT *event_down = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT));\n    ALLEGRO_EVENT *event_up = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT));\n    \n    event_down->type = ALLEGRO_EVENT_KEY_DOWN;\n    event_down->keyboard.display = current_display;\n    event_down->keyboard.keycode = ALLEGRO_KEY_BACKSPACE;\n    event_up->type = ALLEGRO_EVENT_KEY_UP;\n    event_up->keyboard.display = current_display;\n    event_up->keyboard.keycode = ALLEGRO_KEY_BACKSPACE;\n    al_emit_user_event(event_source, event_down, NULL);\n    al_emit_user_event(event_source, event_up, NULL);\n    \n    free(event_down);\n    free(event_up);\n}\n\n- (BOOL)hasText {\n    return YES;\n}\n\n- (void)insertText:(NSString *)text\n{\n    if (!event_source) {\n        NSLog(@\"insertText(): No event source found, not sending events\");\n        return;\n    }\n    \n    ALLEGRO_EVENT *event_down = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT));\n    ALLEGRO_EVENT *event_up = (ALLEGRO_EVENT*)calloc(1, sizeof(ALLEGRO_EVENT));\n    \n    if([text isEqualToString:@\"\\n\"])\n    {\n        event_down->type = ALLEGRO_EVENT_KEY_DOWN;\n        event_down->keyboard.display = current_display;\n        event_down->keyboard.keycode = ALLEGRO_KEY_ENTER;\n        event_up->type = ALLEGRO_EVENT_KEY_UP;\n        event_up->keyboard.display = current_display;\n        event_up->keyboard.keycode = ALLEGRO_KEY_ENTER;\n        al_emit_user_event(event_source, event_down, NULL);\n        al_emit_user_event(event_source, event_up, NULL);\n        [self hide];\n        //m_kb->setDonePressed();\n    }\n    else {\n        event_down->type = ALLEGRO_EVENT_KEY_CHAR;\n        event_down->keyboard.display = current_display;\n        event_down->keyboard.unichar = [text characterAtIndex:0];\n        // doesn't matter what keycode is, nuklear backend ignores it as long as it\n        // isn't a special key\n        event_down->keyboard.keycode = ALLEGRO_KEY_A;\n        al_emit_user_event(event_source, event_down, NULL);\n    }\n    free(event_down);\n    free(event_up);\n}\n\n-(void)show {\n    NSLog(@\"Should be showing!\");\n [self performSelectorOnMainThread:@selector(becomeFirstResponder) withObject:nil waitUntilDone:YES];\n}\n-(void)hide {\n    NSLog(@\"Should be hiding!\");\n    [self performSelectorOnMainThread:@selector(resignFirstResponder) withObject:nil waitUntilDone:YES];\n}\n- (void)keyboardDidHide:(NSNotification *)notification {\n    NSLog(@\"keyboardDidHide called\");\n}\n\n-(void)dealloc {\n    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidHideNotification object:nil];\n}\n@end\n"
  },
  {
    "path": "demo/allegro5/Makefile",
    "content": "# Install\nBIN = demo\n\n# Flags\nCFLAGS += -std=c89 -Wall -Wextra -pedantic -Wno-unused-function\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\n# TODO: Handle Windows build\n#ifeq ($(OS),Windows_NT)\n#BIN := $(BIN).exe\n#LIBS = -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32\n#else\nLIBS = -lallegro -lallegro_main -lallegro_image -lallegro_font \\\n\t-lallegro_ttf -lallegro_primitives -lm\n#endif\n\n$(BIN):\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)\n"
  },
  {
    "path": "demo/allegro5/Readme.md",
    "content": "# Allegro v5 nuklear backend\n\nThis backend provides support for [Allegro version 5](https://liballeg.github.io). It works on on all supported platforms with an OpenGL backend, including iOS and Android.\n\nTouch support is provided by handling the first touch (ignoring any extra simultaneous touches) and emitting nuklear mouse events. nuklear will handle only the first touch like a single left-mouse click. Dragging the touch screen emits mouse-move events.\n\n## Compiling\nYou must link with image, font, ttf, and primitives Allegro addons. See the `Makefile`.\n\n## Resolutions\n\nLike every nuklear backend, handling many different resolutions and resolution densities can be tricky. 14px font on a desktop may be perfect, but extremely small on a retina iPad. I recommend writing a middleware that will detect what kind of screen is being used, and modify the sizes of widgets accordingly.\n\n## Soft Keyboard for Touch Screen Devices\n\nInformation on how to implement soft keyboard callbacks for Android can be on the Allegro community wiki: https://wiki.allegro.cc/index.php?title=Running_Allegro_applications_on_Android#Displaying_the_Android_keyboard\n\nTo display a soft keyboard on iOS, you must create a `UIView` subclass that implements the `UIKeyInput` interface. See `KeyboardHandleriOS.h` and `KeyboardHandleriOS.m` Objective-C source code files for an example on how to do this. As the Allegro keyboard driver does not currently listen for iOS events, we use a custom event emitter to emit keyboard events, which is passed in after initialization with `(void)setCustomKeyboardEventSource:(ALLEGRO_EVENT_SOURCE *)ev_src`. This causes normal keyboard events to be emitted and properly caught by the nuklear backend. The provided `main.c` demo file does not implement this, but with the provided source code files it is not difficult to do. See this Allegro community forum thread for more information: https://www.allegro.cc/forums/thread/616672\n\nTo know when nuklear wants to open and close the keyboard, you can check edit widget flags:\n\n```\nnk_flags ed_flags = nk_edit_string(ctx, NK_EDIT_FIELD, field_buffer, &field_len, 64, nk_filter_default);\nif (ed_flags & NK_EDIT_ACTIVATED)\n    open_ios_soft_keyboard();\nif (ed_flags &  NK_EDIT_DEACTIVATED)\n    close_ios_soft_keyboard();\n```\n\n### Manual Soft Keyboard Dismissal\nAs the user can dismiss a keyboard manually, nuklear will not be aware when this occurs, and the text edit cursor will think the entry field is still active. I recommend catching the dismiss event, then emitting `ALLEGRO_EVENT_TOUCH_BEGIN` and `ALLEGRO_EVENT_TOUCH_END` events in an unused portion of the screen (like the bottom-right corner). This will simulate the user touching outside of the text entry widget, which will make the edit field inactive.\n\n### The Keyboard Covers Widgets\n\nIf you have a widget near the bottom of the screen, the keyboard opening woll cover it, and the user won't see what they are entering. One way to handle this is to make all text edit widgets view-only, and when tapped you dynamically create a new widget above the keyboard that receives all the key strokes. When the user dismisses the keyboard, copy the result from the new widget into the existing read-only text view and destroy the dynamic one."
  },
  {
    "path": "demo/allegro5/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <limits.h>\n#include <time.h>\n\n#include <allegro5/allegro.h>\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_IMPLEMENTATION\n#define NK_ALLEGRO5_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_allegro5.h\"\n\n\n#define UNUSED(a) (void)a\n#define MIN(a,b) ((a) < (b) ? (a) : (b))\n#define MAX(a,b) ((a) < (b) ? (b) : (a))\n#define LEN(a) (sizeof(a)/sizeof(a)[0])\n\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nint main(void)\n{\n    /* Platform */\n    ALLEGRO_DISPLAY *display = NULL;\n    ALLEGRO_EVENT_QUEUE *event_queue = NULL;\n    NkAllegro5Font *font;\n    struct nk_context *ctx;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    if (!al_init()) {\n        fprintf(stdout, \"failed to initialize allegro5!\\n\");\n        exit(1);\n    }\n\n    al_install_mouse();\n    al_set_mouse_wheel_precision(150);\n    al_install_keyboard();\n\n    al_set_new_display_flags(ALLEGRO_WINDOWED|ALLEGRO_RESIZABLE|ALLEGRO_OPENGL);\n    al_set_new_display_option(ALLEGRO_SAMPLE_BUFFERS, 1, ALLEGRO_SUGGEST);\n    al_set_new_display_option(ALLEGRO_SAMPLES, 8, ALLEGRO_SUGGEST);\n    display = al_create_display(WINDOW_WIDTH, WINDOW_HEIGHT);\n    if (!display) {\n        fprintf(stdout, \"failed to create display!\\n\");\n        exit(1);\n    }\n\n    event_queue = al_create_event_queue();\n    if (!event_queue) {\n        fprintf(stdout, \"failed to create event_queue!\\n\");\n        al_destroy_display(display);\n        exit(1);\n    }\n\n    al_register_event_source(event_queue, al_get_display_event_source(display));\n    al_register_event_source(event_queue, al_get_mouse_event_source());\n    al_register_event_source(event_queue, al_get_keyboard_event_source());\n\n    font = nk_allegro5_font_create_from_file(\"../../extra_font/Roboto-Regular.ttf\", 12, 0);\n\n    ctx = nk_allegro5_init(font, display, WINDOW_WIDTH, WINDOW_HEIGHT);\n\n    while(1)\n    {\n        bool get_event;\n        ALLEGRO_EVENT ev;\n        ALLEGRO_TIMEOUT timeout;\n        al_init_timeout(&timeout, 0.06);\n\n        get_event = al_wait_for_event_until(event_queue, &ev, &timeout);\n\n        if (get_event && ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {\n            break;\n        }\n\n        /* Very Important: Always do nk_input_begin / nk_input_end even if\n           there are no events, otherwise internal nuklear state gets messed up */\n        nk_input_begin(ctx);\n        if (get_event) {\n            while (get_event) {\n                nk_allegro5_handle_event(&ev);\n                get_event = al_get_next_event(event_queue, &ev);\n            }\n        }\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 200, 200),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 22, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        al_clear_to_color(al_map_rgb(19, 43, 81));\n        /* IMPORTANT: `nk_allegro5_render` changes the target backbuffer\n        to the display set at initialization and does not restore it.\n        Change it if you want to draw somewhere else. */\n        nk_allegro5_render();\n        al_flip_display();\n    }\n\n    nk_allegro5_font_del(font);\n    nk_allegro5_shutdown();\n    al_destroy_display(display);\n    al_destroy_event_queue(event_queue);\n    return 0;\n}\n\n"
  },
  {
    "path": "demo/allegro5/nuklear_allegro5.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_ALLEGRO5_H_\n#define NK_ALLEGRO5_H_\n\n#include <string.h>\n#include <allegro5/allegro.h>\n#include <allegro5/allegro_image.h>\n#include <allegro5/allegro_primitives.h>\n#include <allegro5/allegro_font.h>\n#include <allegro5/allegro_ttf.h>\n\ntypedef struct NkAllegro5Font NkAllegro5Font;\nNK_API struct nk_context*     nk_allegro5_init(NkAllegro5Font *font, ALLEGRO_DISPLAY *dsp,\n                                  unsigned int width, unsigned int height);\nNK_API int                    nk_allegro5_handle_event(ALLEGRO_EVENT *ev);\nNK_API void                   nk_allegro5_shutdown(void);\nNK_API void                   nk_allegro5_render(void);\n\nNK_API struct nk_image*       nk_allegro5_create_image(const char* file_name);\nNK_API void                   nk_allegro5_del_image(struct nk_image* image);\n\n/* Fonts. We wrap normal allegro fonts in some nuklear book keeping */\nNK_API NkAllegro5Font*        nk_allegro5_font_create_from_file(const char *file_name, int font_size, int flags);\nNK_API void                   nk_allegro5_font_del(NkAllegro5Font *font);\n/* NOTE : just use NkAllegro5Font instead of nk_user_font,\n    since the former just extends the latter*/\nNK_API void                   nk_allegro5_font_set_font(NkAllegro5Font *font);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_ALLEGRO5_IMPLEMENTATION\n#include <stdio.h>\n\n#ifndef NK_ALLEGRO5_TEXT_MAX\n#define NK_ALLEGRO5_TEXT_MAX 256\n#endif\n\n\nstruct NkAllegro5Font {\n    struct nk_user_font nk;\n    ALLEGRO_FONT *font;\n};\n\nstatic struct nk_allegro5 {\n    ALLEGRO_DISPLAY *dsp;\n    unsigned int width;\n    unsigned int height;\n    int is_touch_down;\n    int touch_down_id;\n    struct nk_context ctx;\n    struct nk_buffer cmds;\n    float delta_time_seconds_last;\n} allegro5;\n\n\nNK_API struct nk_image* nk_allegro5_create_image(const char* file_name)\n{\n    ALLEGRO_BITMAP *bitmap;\n    struct nk_image *image;\n    if (!al_init_image_addon()) {\n        fprintf(stdout, \"Unable to initialize required allegro5 image addon\\n\");\n        exit(1);\n    }\n\n    bitmap = al_load_bitmap(file_name);\n    if (bitmap == NULL) {\n        fprintf(stdout, \"Unable to load image file: %s\\n\", file_name);\n        return NULL;\n    }\n\n    image = (struct nk_image*)calloc(1, sizeof(struct nk_image));\n    image->handle.ptr = bitmap;\n    image->w = al_get_bitmap_width(bitmap);\n    image->h = al_get_bitmap_height(bitmap);\n    return image;\n}\n\nNK_API void nk_allegro5_del_image(struct nk_image* image)\n{\n    if(!image) return;\n    al_destroy_bitmap(image->handle.ptr);\n    free(image);\n}\n\nstatic float\nnk_allegro5_font_get_text_width(nk_handle handle, float height, const char *text, int len)\n{\n    float width;\n    char *str;\n    NkAllegro5Font *font = (NkAllegro5Font*)handle.ptr;\n    NK_UNUSED(height);\n    if (!font || !text) {\n        return 0;\n    }\n    /* We must copy into a new buffer with exact length null-terminated\n       as nuklear uses variable size buffers and al_get_text_width doesn't\n       accept a length, it infers length from null-termination\n       (which is unsafe API design by allegro devs!) */\n    str = calloc((size_t)len + 1, 1);\n    if(!str) return 0;\n    strncpy(str, text, len);\n    width = al_get_text_width(font->font, str);\n    free(str);\n    return width;\n}\n\n/* Flags are identical to al_load_font() flags argument */\nNK_API NkAllegro5Font*\nnk_allegro5_font_create_from_file(const char *file_name, int font_size, int flags)\n{\n    NkAllegro5Font *font;\n    if (!al_init_image_addon()) {\n        fprintf(stdout, \"Unable to initialize required allegro5 image addon\\n\");\n        exit(1);\n    }\n    if (!al_init_font_addon()) {\n        fprintf(stdout, \"Unable to initialize required allegro5 font addon\\n\");\n        exit(1);\n    }\n    if (!al_init_ttf_addon()) {\n        fprintf(stdout, \"Unable to initialize required allegro5 TTF font addon\\n\");\n        exit(1);\n    }\n    font = (NkAllegro5Font*)calloc(1, sizeof(NkAllegro5Font));\n\n    font->font = al_load_font(file_name, font_size, flags);\n    if (font->font == NULL) {\n        fprintf(stdout, \"Unable to load font file: %s\\n\", file_name);\n        return NULL;\n    }\n    font->nk.userdata = nk_handle_ptr(font);\n    font->nk.height = (float)al_get_font_line_height(font->font);\n    font->nk.width = nk_allegro5_font_get_text_width;\n    return font;\n}\n\nNK_API void\nnk_allegro5_font_set_font(NkAllegro5Font *allegro5font)\n{\n    struct nk_user_font *font = &allegro5font->nk;\n    nk_style_set_font(&allegro5.ctx, font);\n}\n\nNK_API void\nnk_allegro5_font_del(NkAllegro5Font *font)\n{\n    if(!font) return;\n    al_destroy_font(font->font);\n    free(font);\n}\n\nstatic ALLEGRO_COLOR\nnk_color_to_allegro_color(struct nk_color color)\n{\n    return al_map_rgba((unsigned char)color.r, (unsigned char)color.g,\n                (unsigned char)color.b, (unsigned char)color.a);\n}\n\nNK_API void\nnk_allegro5_render()\n{\n    const struct nk_command *cmd;\n\n    /* Update the timer */\n    float now = (float)al_get_time();\n    allegro5.ctx.delta_time_seconds = now - allegro5.delta_time_seconds_last;\n    allegro5.delta_time_seconds_last = now;\n\n    al_set_target_backbuffer(allegro5.dsp);\n\n    nk_foreach(cmd, &allegro5.ctx)\n    {\n        ALLEGRO_COLOR color;\n        switch (cmd->type) {\n        case NK_COMMAND_NOP: break;\n        case NK_COMMAND_SCISSOR: {\n            const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;\n            al_set_clipping_rectangle((int)s->x, (int)s->y, (int)s->w, (int)s->h);\n        } break;\n        case NK_COMMAND_LINE: {\n            const struct nk_command_line *l = (const struct nk_command_line *)cmd;\n            color = nk_color_to_allegro_color(l->color);\n            al_draw_line((float)l->begin.x, (float)l->begin.y, (float)l->end.x,\n                (float)l->end.y, color, (float)l->line_thickness);\n        } break;\n        case NK_COMMAND_RECT: {\n            const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;\n            color = nk_color_to_allegro_color(r->color);\n            al_draw_rounded_rectangle((float)r->x, (float)r->y, (float)(r->x + r->w),\n                (float)(r->y + r->h), (float)r->rounding, (float)r->rounding, color,\n                (float)r->line_thickness);\n        } break;\n        case NK_COMMAND_RECT_FILLED: {\n            const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;\n            color = nk_color_to_allegro_color(r->color);\n            al_draw_filled_rounded_rectangle((float)r->x, (float)r->y,\n                (float)(r->x + r->w), (float)(r->y + r->h), (float)r->rounding,\n                (float)r->rounding, color);\n        } break;\n        case NK_COMMAND_CIRCLE: {\n            float xr, yr;\n            const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;\n            color = nk_color_to_allegro_color(c->color);\n            xr = (float)c->w/2;\n            yr = (float)c->h/2;\n            al_draw_ellipse(((float)(c->x)) + xr, ((float)c->y) + yr,\n                xr, yr, color, (float)c->line_thickness);\n        } break;\n        case NK_COMMAND_CIRCLE_FILLED: {\n            float xr, yr;\n            const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;\n            color = nk_color_to_allegro_color(c->color);\n            xr = (float)c->w/2;\n            yr = (float)c->h/2;\n            al_draw_filled_ellipse(((float)(c->x)) + xr, ((float)c->y) + yr,\n                xr, yr, color);\n        } break;\n        case NK_COMMAND_TRIANGLE: {\n            const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;\n            color = nk_color_to_allegro_color(t->color);\n            al_draw_triangle((float)t->a.x, (float)t->a.y, (float)t->b.x, (float)t->b.y,\n                (float)t->c.x, (float)t->c.y, color, (float)t->line_thickness);\n        } break;\n        case NK_COMMAND_TRIANGLE_FILLED: {\n            const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;\n            color = nk_color_to_allegro_color(t->color);\n            al_draw_filled_triangle((float)t->a.x, (float)t->a.y, (float)t->b.x,\n                (float)t->b.y, (float)t->c.x, (float)t->c.y, color);\n        } break;\n        case NK_COMMAND_POLYGON: {\n            int i;\n            float *vertices;\n            const struct nk_command_polygon *p = (const struct nk_command_polygon*)cmd;\n            vertices = calloc(p->point_count * 2, sizeof(float));\n            color = nk_color_to_allegro_color(p->color);\n            for (i = 0; i < p->point_count; i++) {\n                vertices[i*2] = p->points[i].x;\n                vertices[(i*2) + 1] = p->points[i].y;\n            }\n            al_draw_polyline(vertices, (2 * sizeof(float)),\n                (int)p->point_count, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_CAP_CLOSED,\n                color, (float)p->line_thickness, 0.0);\n            free(vertices);\n        } break;\n        case NK_COMMAND_POLYGON_FILLED: {\n            int i, j = 0;\n            float *vertices;\n            const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;\n            vertices = calloc(p->point_count * 2, sizeof(float));\n            color = nk_color_to_allegro_color(p->color);\n            for (i = p->point_count - 1; i >= 0; i--) {\n                vertices[j++] = p->points[i].x;\n                vertices[j++] = p->points[i].y;\n            }\n            al_draw_filled_polygon(vertices, (int)p->point_count, color);\n            free(vertices);\n        } break;\n        case NK_COMMAND_POLYLINE: {\n            int i;\n            float *vertices;\n            const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;\n            vertices = calloc(p->point_count * 2, sizeof(float));\n            color = nk_color_to_allegro_color(p->color);\n            for (i = 0; i < p->point_count; i++) {\n                vertices[i*2] = p->points[i].x;\n                vertices[(i*2) + 1] = p->points[i].y;\n            }\n            al_draw_polyline(vertices, (2 * sizeof(float)),\n                (int)p->point_count, ALLEGRO_LINE_JOIN_ROUND, ALLEGRO_LINE_CAP_ROUND,\n                color, (float)p->line_thickness, 0.0);\n            free(vertices);\n        } break;\n        case NK_COMMAND_TEXT: {\n            NkAllegro5Font *font;\n            const struct nk_command_text *t = (const struct nk_command_text*)cmd;\n            color = nk_color_to_allegro_color(t->foreground);\n            font = (NkAllegro5Font*)t->font->userdata.ptr;\n            al_draw_text(font->font,\n                color, (float)t->x, (float)t->y, 0,\n                (const char*)t->string);\n        } break;\n        case NK_COMMAND_CURVE: {\n            float points[8];\n            const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;\n            color = nk_color_to_allegro_color(q->color);\n            points[0] = (float)q->begin.x;\n            points[1] = (float)q->begin.y;\n            points[2] = (float)q->ctrl[0].x;\n            points[3] = (float)q->ctrl[0].y;\n            points[4] = (float)q->ctrl[1].x;\n            points[5] = (float)q->ctrl[1].y;\n            points[6] = (float)q->end.x;\n            points[7] = (float)q->end.y;\n            al_draw_spline(points, color, (float)q->line_thickness);\n        } break;\n        case NK_COMMAND_ARC: {\n            const struct nk_command_arc *a = (const struct nk_command_arc *)cmd;\n            color = nk_color_to_allegro_color(a->color);\n            al_draw_pieslice((float)a->cx, (float)a->cy, (float)a->r, a->a[0],\n                a->a[1], color, (float)a->line_thickness);\n        } break;\n        case NK_COMMAND_ARC_FILLED: {\n            const struct nk_command_arc_filled *a = (const struct nk_command_arc_filled *)cmd;\n            color = nk_color_to_allegro_color(a->color);\n            al_draw_filled_pieslice((float)a->cx, (float)a->cy, (float)a->r, a->a[0],\n                a->a[1], color);\n        } break;\n        case NK_COMMAND_IMAGE: {\n            const struct nk_command_image *i = (const struct nk_command_image *)cmd;\n            nk_ushort\n                x = i->img.region[0],\n                y = i->img.region[1],\n                w = i->img.region[2],\n                h = i->img.region[3];\n            if(w == 0 && h == 0)\n            {\n                x = i->x; y = i->y; w = i->w; h = i->h;\n            }\n            al_draw_scaled_bitmap(i->img.handle.ptr,\n                                  x, y, w, h, i->x, i->y, i->w, i->h, 0);\n        } break;\n        case NK_COMMAND_RECT_MULTI_COLOR:\n        default: break;\n        }\n    }\n    nk_clear(&allegro5.ctx);\n}\n\nNK_API int\nnk_allegro5_handle_event(ALLEGRO_EVENT *ev)\n{\n    struct nk_context *ctx = &allegro5.ctx;\n    static int insert_toggle = 0;\n    switch (ev->type) {\n        case ALLEGRO_EVENT_DISPLAY_RESIZE: {\n            allegro5.width = (unsigned int)ev->display.width;\n            allegro5.height = (unsigned int)ev->display.height;\n            al_acknowledge_resize(ev->display.source);\n            return 1;\n        } break;\n        case ALLEGRO_EVENT_MOUSE_AXES: {\n            nk_input_motion(ctx, ev->mouse.x, ev->mouse.y);\n            if (ev->mouse.dz != 0) {\n                nk_input_scroll(ctx, nk_vec2(0,(float)ev->mouse.dz / al_get_mouse_wheel_precision()));\n            }\n            return 1;\n        } break;\n        case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:\n        case ALLEGRO_EVENT_MOUSE_BUTTON_UP: {\n            int button;\n            switch (ev->mouse.button) {\n                case 1: button = NK_BUTTON_LEFT; break;\n                case 2: button = NK_BUTTON_RIGHT; break;\n                case 3: button = NK_BUTTON_MIDDLE; break;\n                case 4: button = NK_BUTTON_X1; break;\n                case 5: button = NK_BUTTON_X2; break;\n                default: return 0;\n            }\n            nk_input_button(ctx, button, ev->mouse.x, ev->mouse.y, ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN);\n            return 1;\n        } break;\n        /* This essentially converts touch events to mouse events */\n        case ALLEGRO_EVENT_TOUCH_BEGIN:\n        case ALLEGRO_EVENT_TOUCH_END: {\n            /* We only acknowledge one touch at a time. Otherwise, each touch\n               would be manipulating multiple nuklear elements, as if there\n               were multiple mouse cursors */\n            if (allegro5.is_touch_down && allegro5.touch_down_id != ev->touch.id) {\n                return 0;\n            }\n            if (ev->type == ALLEGRO_EVENT_TOUCH_BEGIN) {\n                allegro5.is_touch_down = 1;\n                allegro5.touch_down_id = ev->touch.id;\n                /* FIXME: This is a hack to properly simulate\n                   touches as a mouse with nuklear. If you instantly jump\n                   from one place to another without an nk_input_end(), it\n                   confuses the nuklear state. nuklear expects smooth mouse\n                   movements, which is unlike a touch screen */\n                nk_input_motion(ctx, (int)ev->touch.x, (int)ev->touch.y);\n                nk_input_end(ctx);\n                nk_input_begin(ctx);\n            }\n            else {\n                allegro5.is_touch_down = 0;\n                allegro5.touch_down_id = -1;\n            }\n            nk_input_button(ctx, NK_BUTTON_LEFT, (int)ev->touch.x, (int)ev->touch.y, ev->type == ALLEGRO_EVENT_TOUCH_BEGIN);\n            return 1;\n        } break;\n        case ALLEGRO_EVENT_TOUCH_MOVE: {\n            /* Only acknowledge movements of a single touch, we are\n               simulating a mouse cursor */\n            if (!allegro5.is_touch_down || allegro5.touch_down_id != ev->touch.id) {\n                return 0;\n            }\n            nk_input_motion(ctx, (int)ev->touch.x, (int)ev->touch.y);\n            return 1;\n        } break;\n        case ALLEGRO_EVENT_KEY_DOWN:\n        case ALLEGRO_EVENT_KEY_UP: {\n            int kc = ev->keyboard.keycode;\n            int down = ev->type == ALLEGRO_EVENT_KEY_DOWN;\n\n            /* do we need this? */\n            if (kc == ALLEGRO_KEY_LSHIFT || kc == ALLEGRO_KEY_RSHIFT) nk_input_key(ctx, NK_KEY_SHIFT, down);\n            else if (kc == ALLEGRO_KEY_ESCAPE)    nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down);\n            else if (kc == ALLEGRO_KEY_PGUP)      nk_input_key(ctx, NK_KEY_SCROLL_UP, down);\n            else if (kc == ALLEGRO_KEY_PGDN)      nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);\n            else if (kc == ALLEGRO_KEY_INSERT) {\n                if (down) insert_toggle = !insert_toggle;\n                if (insert_toggle) {\n                    nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);\n                    /* nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, !down); */\n                } else {\n                    nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);\n                    /* nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, !down); */\n                }\n            } else if (kc == ALLEGRO_KEY_HOME) {\n                nk_input_key(ctx, NK_KEY_TEXT_START, down);\n                nk_input_key(ctx, NK_KEY_SCROLL_START, down);\n            } else if (kc == ALLEGRO_KEY_END) {\n                nk_input_key(ctx, NK_KEY_TEXT_END, down);\n                nk_input_key(ctx, NK_KEY_SCROLL_END, down);\n            }\n            return 1;\n        } break;\n        case ALLEGRO_EVENT_KEY_CHAR: {\n            int kc = ev->keyboard.keycode;\n            int repeat = ev->keyboard.repeat;\n            int control_mask = (ev->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) ||\n                               (ev->keyboard.modifiers & ALLEGRO_KEYMOD_COMMAND);\n\n            if (kc == ALLEGRO_KEY_C && control_mask && !repeat) {\n                nk_input_key(ctx, NK_KEY_COPY, 1);\n            } else if (kc == ALLEGRO_KEY_V && control_mask) {\n                nk_input_key(ctx, NK_KEY_PASTE, 1);\n            } else if (kc == ALLEGRO_KEY_X && control_mask && !repeat) {\n                nk_input_key(ctx, NK_KEY_CUT, 1);\n            } else if (kc == ALLEGRO_KEY_Z && control_mask) {\n                nk_input_key(ctx, NK_KEY_TEXT_UNDO, 1);\n            } else if (kc == ALLEGRO_KEY_R && control_mask) {\n                nk_input_key(ctx, NK_KEY_TEXT_REDO, 1);\n            } else if (kc == ALLEGRO_KEY_A && control_mask && !repeat) {\n                nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, 1);\n            } else if (kc == ALLEGRO_KEY_BACKSPACE) {\n                nk_input_key(ctx, NK_KEY_BACKSPACE, 1);\n            } else if (kc == ALLEGRO_KEY_LEFT) {\n                if (control_mask) {\n                    nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, 1);\n                } else {\n                    nk_input_key(ctx, NK_KEY_LEFT, 1);\n                }\n            } else if (kc == ALLEGRO_KEY_RIGHT) {\n                if (control_mask) {\n                    nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, 1);\n                } else {\n                    nk_input_key(ctx, NK_KEY_RIGHT, 1);\n                }\n            } else if (kc == ALLEGRO_KEY_UP) {\n                nk_input_key(ctx, NK_KEY_UP, 1);\n            } else if (kc == ALLEGRO_KEY_DOWN) {\n                nk_input_key(ctx, NK_KEY_DOWN, 1);\n            } else if (kc == ALLEGRO_KEY_DELETE) {\n                nk_input_key(ctx, NK_KEY_DEL, 1);\n            } else if (kc == ALLEGRO_KEY_ENTER || kc == ALLEGRO_KEY_PAD_ENTER) {\n                nk_input_key(ctx, NK_KEY_ENTER, 1);\n            } else if (kc == ALLEGRO_KEY_TAB) {\n                nk_input_key(ctx, NK_KEY_TAB, 1);\n            } else {\n                if (kc != ALLEGRO_KEY_BACKSPACE &&\n                    kc != ALLEGRO_KEY_HOME &&\n                    kc != ALLEGRO_KEY_END &&\n                    kc != ALLEGRO_KEY_ESCAPE &&\n                    kc != ALLEGRO_KEY_INSERT &&\n                    kc != ALLEGRO_KEY_PGDN &&\n                    kc != ALLEGRO_KEY_PGUP) {\n                    nk_input_unicode(ctx, ev->keyboard.unichar);\n                }\n            }\n            return 1;\n        } break;\n        default: return 0; break;\n    }\n}\n\nNK_INTERN void\nnk_allegro5_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    char *text = al_get_clipboard_text(allegro5.dsp);\n    if (text) nk_textedit_paste(edit, text, nk_strlen(text));\n    (void)usr;\n    al_free(text);\n}\n\nNK_INTERN void\nnk_allegro5_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    char *str = 0;\n    (void)usr;\n    if (!len) return;\n    str = calloc((size_t)len + 1, 1);\n    if (!str) return;\n    strncpy(str, text, len);\n    al_set_clipboard_text(allegro5.dsp, str);\n    free(str);\n}\n\nNK_API struct nk_context*\nnk_allegro5_init(NkAllegro5Font *allegro5font, ALLEGRO_DISPLAY *dsp,\n    unsigned int width, unsigned int height)\n{\n    struct nk_user_font *font;\n    if (!al_init_primitives_addon()) {\n        fprintf(stdout, \"Unable to initialize required allegro5 primitives addon\\n\");\n        exit(1);\n    }\n\n    font = &allegro5font->nk;\n\n    allegro5.dsp = dsp;\n    allegro5.width = width;\n    allegro5.height = height;\n    allegro5.is_touch_down = 0;\n    allegro5.touch_down_id = -1;\n    allegro5.delta_time_seconds_last = (float)al_get_time();\n\n    nk_init_default(&allegro5.ctx, font);\n    allegro5.ctx.clip.copy = nk_allegro5_clipboard_copy;\n    allegro5.ctx.clip.paste = nk_allegro5_clipboard_paste;\n    allegro5.ctx.clip.userdata = nk_handle_ptr(0);\n    return &allegro5.ctx;\n}\n\nNK_API\nvoid nk_allegro5_shutdown(void)\n{\n    nk_free(&allegro5.ctx);\n    memset(&allegro5, 0, sizeof(allegro5));\n}\n\n#endif /* NK_ALLEGRO5_IMPLEMENTATION */\n\n"
  },
  {
    "path": "demo/common/calculator.c",
    "content": "/* nuklear - v1.00 - public domain */\nstatic void\ncalculator(struct nk_context *ctx)\n{\n    if (nk_begin(ctx, \"Calculator\", nk_rect(10, 10, 180, 250),\n        NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE))\n    {\n        static int set = 0, prev = 0, op = 0;\n        static const char numbers[] = \"789456123\";\n        static const char ops[] = \"+-*/\";\n        static double a = 0, b = 0;\n        static double *current = &a;\n\n        size_t i = 0;\n        int solve = 0;\n        {int len; char buffer[256];\n        nk_layout_row_dynamic(ctx, 35, 1);\n        len = snprintf(buffer, 256, \"%.2f\", *current);\n        nk_edit_string(ctx, NK_EDIT_SIMPLE, buffer, &len, 255, nk_filter_float);\n        buffer[len] = 0;\n        *current = atof(buffer);}\n\n        nk_layout_row_dynamic(ctx, 35, 4);\n        for (i = 0; i < 16; ++i) {\n            if (i >= 12 && i < 15) {\n                if (i > 12) continue;\n                if (nk_button_label(ctx, \"C\")) {\n                    a = b = op = 0; current = &a; set = 0;\n                } if (nk_button_label(ctx, \"0\")) {\n                    *current = *current*10.0f; set = 0;\n                } if (nk_button_label(ctx, \"=\")) {\n                    solve = 1; prev = op; op = 0;\n                }\n            } else if (((i+1) % 4)) {\n                if (nk_button_text(ctx, &numbers[(i/4)*3+i%4], 1)) {\n                    *current = *current * 10.0f + numbers[(i/4)*3+i%4] - '0';\n                    set = 0;\n                }\n            } else if (nk_button_text(ctx, &ops[i/4], 1)) {\n                if (!set) {\n                    if (current != &b) {\n                        current = &b;\n                    } else {\n                        prev = op;\n                        solve = 1;\n                    }\n                }\n                op = ops[i/4];\n                set = 1;\n            }\n        }\n        if (solve) {\n            if (prev == '+') a = a + b;\n            if (prev == '-') a = a - b;\n            if (prev == '*') a = a * b;\n            if (prev == '/') a = a / b;\n            current = &a;\n            if (set) current = &b;\n            b = 0; set = 0;\n        }\n    }\n    nk_end(ctx);\n}\n\n"
  },
  {
    "path": "demo/common/canvas.c",
    "content": "/* nuklear - v1.05 - public domain */\nstruct nk_canvas {\n    struct nk_command_buffer *painter;\n    struct nk_vec2 item_spacing;\n    struct nk_vec2 panel_padding;\n    struct nk_style_item window_background;\n};\n\nstatic nk_bool\ncanvas_begin(struct nk_context *ctx, struct nk_canvas *canvas, nk_flags flags,\n    int x, int y, int width, int height, struct nk_color background_color)\n{\n    /* save style properties which will be overwritten */\n    canvas->panel_padding = ctx->style.window.padding;\n    canvas->item_spacing = ctx->style.window.spacing;\n    canvas->window_background = ctx->style.window.fixed_background;\n\n    /* use the complete window space and set background */\n    ctx->style.window.spacing = nk_vec2(0,0);\n    ctx->style.window.padding = nk_vec2(0,0);\n    ctx->style.window.fixed_background = nk_style_item_color(background_color);\n\n    /* create/update window and set position + size */\n    if (!nk_begin(ctx, \"Canvas\", nk_rect(x, y, width, height), NK_WINDOW_NO_SCROLLBAR|flags))\n        return nk_false;\n\n    /* allocate the complete window space for drawing */\n    {\n        struct nk_rect total_space;\n        total_space = nk_window_get_content_region(ctx);\n        nk_layout_row_dynamic(ctx, total_space.h, 1);\n        nk_widget(&total_space, ctx);\n        canvas->painter = nk_window_get_canvas(ctx);\n    }\n\n    return nk_true;\n}\n\nstatic void\ncanvas_end(struct nk_context *ctx, struct nk_canvas *canvas)\n{\n    nk_end(ctx);\n    ctx->style.window.spacing = canvas->panel_padding;\n    ctx->style.window.padding = canvas->item_spacing;\n    ctx->style.window.fixed_background = canvas->window_background;\n}\n\nstatic void\ncanvas(struct nk_context *ctx)\n{\n        struct nk_canvas canvas;\n        if (canvas_begin(ctx, &canvas, NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE, 10, 10, 500, 550, nk_rgb(250,250,250)))\n        {\n            float x = canvas.painter->clip.x, y = canvas.painter->clip.y;\n\n            nk_fill_rect(canvas.painter, nk_rect(x + 15, y + 15, 210, 210), 5, nk_rgb(247, 230, 154));\n            nk_fill_rect(canvas.painter, nk_rect(x + 20, y + 20, 200, 200), 5, nk_rgb(188, 174, 118));\n            /* nk_draw_text(canvas.painter, nk_rect(x + 30, y + 30, 150, 20), \"Text to draw\", 12, &font->handle, nk_rgb(188,174,118), nk_rgb(0,0,0)); */\n            nk_fill_rect(canvas.painter, nk_rect(x + 250, y + 20, 100, 100), 0, nk_rgb(0,0,255));\n            nk_fill_circle(canvas.painter, nk_rect(x + 20, y + 250, 100, 100), nk_rgb(255,0,0));\n            nk_fill_triangle(canvas.painter, x + 250, y + 250, x + 350, y + 250, x + 300, y + 350, nk_rgb(0,255,0));\n            nk_fill_arc(canvas.painter, x + 300, y + 420, 50, 0, 3.141592654f * 3.0f / 4.0f, nk_rgb(255,255,0));\n\n            {\n                float points[12];\n                points[0]  = x + 200; points[1]  = y + 250;\n                points[2]  = x + 250; points[3]  = y + 350;\n                points[4]  = x + 225; points[5]  = y + 350;\n                points[6]  = x + 200; points[7]  = y + 300;\n                points[8]  = x + 175; points[9]  = y + 350;\n                points[10] = x + 150; points[11] = y + 350;\n                nk_fill_polygon(canvas.painter, points, 6, nk_rgb(0,0,0));\n            }\n\n            {\n                float points[12];\n                points[0]  = x + 200; points[1]  = y + 370;\n                points[2]  = x + 250; points[3]  = y + 470;\n                points[4]  = x + 225; points[5]  = y + 470;\n                points[6]  = x + 200; points[7]  = y + 420;\n                points[8]  = x + 175; points[9]  = y + 470;\n                points[10] = x + 150; points[11] = y + 470;\n                nk_stroke_polygon(canvas.painter, points, 6, 4, nk_rgb(0,0,0));\n            }\n\n            {\n                float points[8];\n                points[0]  = x + 250; points[1]  = y + 200;\n                points[2]  = x + 275; points[3]  = y + 220;\n                points[4]  = x + 325; points[5]  = y + 170;\n                points[6]  = x + 350; points[7]  = y + 200;\n                nk_stroke_polyline(canvas.painter, points, 4, 2, nk_rgb(255,128,0));\n            }\n\n            nk_stroke_line(canvas.painter, x + 15, y + 10, x + 200, y + 10, 2.0f, nk_rgb(189,45,75));\n            nk_stroke_rect(canvas.painter, nk_rect(x + 370, y + 20, 100, 100), 10, 3, nk_rgb(0,0,255));\n            nk_stroke_curve(canvas.painter, x + 380, y + 200, x + 405, y + 270, x + 455, y + 120, x + 480, y + 200, 2, nk_rgb(0,150,220));\n            nk_stroke_circle(canvas.painter, nk_rect(x + 20, y + 370, 100, 100), 5, nk_rgb(0,255,120));\n            nk_stroke_triangle(canvas.painter, x + 370, y + 250, x + 470, y + 250, x + 420, y + 350, 6, nk_rgb(255,0,143));\n            nk_stroke_arc(canvas.painter, x + 420, y + 420, 50, 0, 3.141592654f * 3.0f / 4.0f, 5, nk_rgb(0,255,255));\n        }\n        canvas_end(ctx, &canvas);\n}\n\n"
  },
  {
    "path": "demo/common/file_browser.c",
    "content": "#include <string.h> // strcpy, strlen\n\n#ifdef __unix__\n#include <dirent.h>\n#include <unistd.h>\n#endif\n\n#ifndef _WIN32\n# include <pwd.h>\n#endif\n\nstruct icons {\n    struct nk_image desktop;\n    struct nk_image home;\n    struct nk_image computer;\n    struct nk_image directory;\n\n    struct nk_image default_file;\n    struct nk_image text_file;\n    struct nk_image music_file;\n    struct nk_image font_file;\n    struct nk_image img_file;\n    struct nk_image movie_file;\n};\n\nenum file_groups {\n    FILE_GROUP_DEFAULT,\n    FILE_GROUP_TEXT,\n    FILE_GROUP_MUSIC,\n    FILE_GROUP_FONT,\n    FILE_GROUP_IMAGE,\n    FILE_GROUP_MOVIE,\n    FILE_GROUP_MAX\n};\n\nenum file_types {\n    FILE_DEFAULT,\n    FILE_TEXT,\n    FILE_C_SOURCE,\n    FILE_CPP_SOURCE,\n    FILE_HEADER,\n    FILE_CPP_HEADER,\n    FILE_MP3,\n    FILE_WAV,\n    FILE_OGG,\n    FILE_TTF,\n    FILE_BMP,\n    FILE_PNG,\n    FILE_JPEG,\n    FILE_PCX,\n    FILE_TGA,\n    FILE_GIF,\n    FILE_MAX\n};\n\nstruct file_group {\n    enum file_groups group;\n    const char *name;\n    struct nk_image *icon;\n};\n\nstruct file {\n    enum file_types type;\n    const char *suffix;\n    enum file_groups group;\n};\n\nstruct media {\n    int font;\n    int icon_sheet;\n    struct icons icons;\n    struct file_group group[FILE_GROUP_MAX];\n    struct file files[FILE_MAX];\n};\n\n#define MAX_PATH_LEN 512\nstruct file_browser {\n    /* path */\n    char file[MAX_PATH_LEN];\n    char home[MAX_PATH_LEN];\n    char desktop[MAX_PATH_LEN];\n    char directory[MAX_PATH_LEN];\n\n    /* directory content */\n    char **files;\n    char **directories;\n    size_t file_count;\n    size_t dir_count;\n    struct media *media;\n};\n\nstatic void\ndie(const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    fputs(\"\\n\", stderr);\n    exit(EXIT_FAILURE);\n}\n\nstatic struct nk_image\nicon_load(const char *filename)\n{\n    int x,y,n;\n    GLuint tex;\n    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);\n    if (!data) die(\"[SDL]: failed to load image: %s\", filename);\n\n    glGenTextures(1, &tex);\n    glBindTexture(GL_TEXTURE_2D, tex);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);\n    glGenerateMipmap(GL_TEXTURE_2D);\n    stbi_image_free(data);\n    return nk_image_id((int)tex);\n}\n\n#if 0\nstatic char*\nfile_load(const char* path, size_t* siz)\n{\n    char *buf;\n    FILE *fd = fopen(path, \"rb\");\n    if (!fd) die(\"Failed to open file: %s\\n\", path);\n    fseek(fd, 0, SEEK_END);\n    *siz = (size_t)ftell(fd);\n    fseek(fd, 0, SEEK_SET);\n    buf = (char*)calloc(*siz, 1);\n    fread(buf, *siz, 1, fd);\n    fclose(fd);\n    return buf;\n}\n#endif\n\nstatic char*\nstr_duplicate(const char *src)\n{\n    char *ret;\n    size_t len = strlen(src);\n    if (!len) return 0;\n    ret = (char*)malloc(len+1);\n    if (!ret) return 0;\n    memcpy(ret, src, len);\n    ret[len] = '\\0';\n    return ret;\n}\n\nstatic void\ndir_free_list(char **list, size_t size)\n{\n    size_t i;\n    for (i = 0; i < size; ++i)\n        free(list[i]);\n    free(list);\n}\n\nstatic char**\ndir_list(const char *dir, int return_subdirs, size_t *count)\n{\n    size_t n = 0;\n    char buffer[MAX_PATH_LEN];\n    char **results = NULL;\n    const DIR *none = NULL;\n    size_t capacity = 32;\n    size_t size;\n    DIR *z;\n\n    assert(dir);\n    assert(count);\n    strncpy(buffer, dir, MAX_PATH_LEN);\n    buffer[MAX_PATH_LEN - 1] = 0;\n    n = strlen(buffer);\n\n    if (n > 0 && (buffer[n-1] != '/'))\n        buffer[n++] = '/';\n\n    size = 0;\n\n    z = opendir(dir);\n    if (z != none) {\n        int nonempty = 1;\n        struct dirent *data = readdir(z);\n        nonempty = (data != NULL);\n        if (!nonempty) return NULL;\n\n        do {\n            DIR *y;\n            char *p;\n            int is_subdir;\n            if (data->d_name[0] == '.')\n                continue;\n\n            strncpy(buffer + n, data->d_name, MAX_PATH_LEN-n);\n            y = opendir(buffer);\n            is_subdir = (y != NULL);\n            if (y != NULL) closedir(y);\n\n            if ((return_subdirs && is_subdir) || (!is_subdir && !return_subdirs)){\n                if (!size) {\n                    results = (char**)calloc(sizeof(char*), capacity);\n                } else if (size >= capacity) {\n                    void *old = results;\n                    capacity = capacity * 2;\n                    results = (char**)realloc(results, capacity * sizeof(char*));\n                    assert(results);\n                    if (!results) free(old);\n                }\n                p = str_duplicate(data->d_name);\n                results[size++] = p;\n            }\n        } while ((data = readdir(z)) != NULL);\n    }\n\n    if (z) closedir(z);\n    *count = size;\n    return results;\n}\n\nstatic struct file_group\nFILE_GROUP(enum file_groups group, const char *name, struct nk_image *icon)\n{\n    struct file_group fg;\n    fg.group = group;\n    fg.name = name;\n    fg.icon = icon;\n    return fg;\n}\n\nstatic struct file\nFILE_DEF(enum file_types type, const char *suffix, enum file_groups group)\n{\n    struct file fd;\n    fd.type = type;\n    fd.suffix = suffix;\n    fd.group = group;\n    return fd;\n}\n\nstatic struct nk_image*\nmedia_icon_for_file(struct media *media, const char *file)\n{\n    int i = 0;\n    const char *s = file;\n    char suffix[4];\n    int found = 0;\n    memset(suffix, 0, sizeof(suffix));\n\n    /* extract suffix .xxx from file */\n    while (*s++ != '\\0') {\n        if (found && i < 3)\n            suffix[i++] = *s;\n\n        if (*s == '.') {\n            if (found){\n                found = 0;\n                break;\n            }\n            found = 1;\n        }\n    }\n\n    /* check for all file definition of all groups for fitting suffix*/\n    for (i = 0; i < FILE_MAX && found; ++i) {\n        struct file *d = &media->files[i];\n        {\n            const char *f = d->suffix;\n            s = suffix;\n            while (f && *f && *s && *s == *f) {\n                s++; f++;\n            }\n\n            /* found correct file definition so */\n            if (f && *s == '\\0' && *f == '\\0')\n                return media->group[d->group].icon;\n        }\n    }\n    return &media->icons.default_file;\n}\n\nstatic void\nmedia_init(struct media *media)\n{\n    /* file groups */\n    struct icons *icons = &media->icons;\n    media->group[FILE_GROUP_DEFAULT] = FILE_GROUP(FILE_GROUP_DEFAULT,\"default\",&icons->default_file);\n    media->group[FILE_GROUP_TEXT] = FILE_GROUP(FILE_GROUP_TEXT, \"textual\", &icons->text_file);\n    media->group[FILE_GROUP_MUSIC] = FILE_GROUP(FILE_GROUP_MUSIC, \"music\", &icons->music_file);\n    media->group[FILE_GROUP_FONT] = FILE_GROUP(FILE_GROUP_FONT, \"font\", &icons->font_file);\n    media->group[FILE_GROUP_IMAGE] = FILE_GROUP(FILE_GROUP_IMAGE, \"image\", &icons->img_file);\n    media->group[FILE_GROUP_MOVIE] = FILE_GROUP(FILE_GROUP_MOVIE, \"movie\", &icons->movie_file);\n\n    /* files */\n    media->files[FILE_DEFAULT] = FILE_DEF(FILE_DEFAULT, NULL, FILE_GROUP_DEFAULT);\n    media->files[FILE_TEXT] = FILE_DEF(FILE_TEXT, \"txt\", FILE_GROUP_TEXT);\n    media->files[FILE_C_SOURCE] = FILE_DEF(FILE_C_SOURCE, \"c\", FILE_GROUP_TEXT);\n    media->files[FILE_CPP_SOURCE] = FILE_DEF(FILE_CPP_SOURCE, \"cpp\", FILE_GROUP_TEXT);\n    media->files[FILE_HEADER] = FILE_DEF(FILE_HEADER, \"h\", FILE_GROUP_TEXT);\n    media->files[FILE_CPP_HEADER] = FILE_DEF(FILE_HEADER, \"hpp\", FILE_GROUP_TEXT);\n    media->files[FILE_MP3] = FILE_DEF(FILE_MP3, \"mp3\", FILE_GROUP_MUSIC);\n    media->files[FILE_WAV] = FILE_DEF(FILE_WAV, \"wav\", FILE_GROUP_MUSIC);\n    media->files[FILE_OGG] = FILE_DEF(FILE_OGG, \"ogg\", FILE_GROUP_MUSIC);\n    media->files[FILE_TTF] = FILE_DEF(FILE_TTF, \"ttf\", FILE_GROUP_FONT);\n    media->files[FILE_BMP] = FILE_DEF(FILE_BMP, \"bmp\", FILE_GROUP_IMAGE);\n    media->files[FILE_PNG] = FILE_DEF(FILE_PNG, \"png\", FILE_GROUP_IMAGE);\n    media->files[FILE_JPEG] = FILE_DEF(FILE_JPEG, \"jpg\", FILE_GROUP_IMAGE);\n    media->files[FILE_PCX] = FILE_DEF(FILE_PCX, \"pcx\", FILE_GROUP_IMAGE);\n    media->files[FILE_TGA] = FILE_DEF(FILE_TGA, \"tga\", FILE_GROUP_IMAGE);\n    media->files[FILE_GIF] = FILE_DEF(FILE_GIF, \"gif\", FILE_GROUP_IMAGE);\n}\n\nstatic void\nfile_browser_reload_directory_content(struct file_browser *browser, const char *path)\n{\n    strncpy(browser->directory, path, MAX_PATH_LEN);\n    browser->directory[MAX_PATH_LEN - 1] = 0;\n    dir_free_list(browser->files, browser->file_count);\n    dir_free_list(browser->directories, browser->dir_count);\n    browser->files = dir_list(path, 0, &browser->file_count);\n    browser->directories = dir_list(path, 1, &browser->dir_count);\n}\n\nstatic void\nfile_browser_init(struct file_browser *browser, struct media *media)\n{\n    memset(browser, 0, sizeof(*browser));\n    browser->media = media;\n    {\n        /* load files and sub-directory list */\n        const char *home = getenv(\"HOME\");\n#ifdef _WIN32\n        if (!home) home = getenv(\"USERPROFILE\");\n#else\n        if (!home) home = getpwuid(getuid())->pw_dir;\n        {\n            size_t l;\n            strncpy(browser->home, home, MAX_PATH_LEN);\n            browser->home[MAX_PATH_LEN - 1] = 0;\n            l = strlen(browser->home);\n            strcpy(browser->home + l, \"/\");\n            strcpy(browser->directory, browser->home);\n        }\n#endif\n        {\n            size_t l;\n            strcpy(browser->desktop, browser->home);\n            l = strlen(browser->desktop);\n            strcpy(browser->desktop + l, \"desktop/\");\n        }\n        browser->files = dir_list(browser->directory, 0, &browser->file_count);\n        browser->directories = dir_list(browser->directory, 1, &browser->dir_count);\n    }\n}\n\nstatic void\nfile_browser_free(struct file_browser *browser)\n{\n    if (browser->files)\n        dir_free_list(browser->files, browser->file_count);\n    if (browser->directories)\n        dir_free_list(browser->directories, browser->dir_count);\n    browser->files = NULL;\n    browser->directories = NULL;\n    memset(browser, 0, sizeof(*browser));\n}\n\nint cmp_fn(const void *str1, const void *str2)\n{\n    const char *str1_ret = *(const char **)str1;\n    const char *str2_ret = *(const char **)str2;\n    return nk_stricmp(str1_ret, str2_ret);\n}\n\nstatic int\nfile_browser_run(struct file_browser *browser, struct nk_context *ctx)\n{\n    int ret = 0;\n    struct media *media = browser->media;\n    struct nk_rect total_space;\n    static nk_bool file_browser_is_open = nk_true;\n\n    if (file_browser_is_open)\n    {\n        if (nk_begin(ctx, \"File Browser\", nk_rect(50, 50, 600, 400),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|NK_WINDOW_NO_SCROLLBAR|\n                NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            static float ratio[] = {0.25f, NK_UNDEFINED};\n            float spacing_x = ctx->style.window.spacing.x;\n\n            /* output path directory selector in the menubar */\n            ctx->style.window.spacing.x = 0;\n            nk_menubar_begin(ctx);\n            {\n                char *d = browser->directory;\n                char *begin = d + 1;\n                nk_layout_row_dynamic(ctx, 25, 6);\n                while (*d++) {\n                    if (*d == '/') {\n                        *d = '\\0';\n                        if (nk_button_label(ctx, begin)) {\n                            *d++ = '/'; *d = '\\0';\n                            file_browser_reload_directory_content(browser, browser->directory);\n                            break;\n                        }\n                        *d = '/';\n                        begin = d + 1;\n                    }\n                }\n            }\n            nk_menubar_end(ctx);\n            ctx->style.window.spacing.x = spacing_x;\n\n            /* window layout */\n            total_space = nk_window_get_content_region(ctx);\n            nk_layout_row(ctx, NK_DYNAMIC, total_space.h - 40, 2, ratio);\n\n            nk_group_begin(ctx, \"Special\", NK_WINDOW_NO_SCROLLBAR);\n            {\n                struct nk_image home = media->icons.home;\n                struct nk_image desktop = media->icons.desktop;\n                struct nk_image computer = media->icons.computer;\n\n                nk_layout_row_dynamic(ctx, 40, 1);\n                if (nk_button_image_label(ctx, home, \"home\", NK_TEXT_CENTERED))\n                    file_browser_reload_directory_content(browser, browser->home);\n                if (nk_button_image_label(ctx,desktop,\"desktop\",NK_TEXT_CENTERED))\n                    file_browser_reload_directory_content(browser, browser->desktop);\n                if (nk_button_image_label(ctx,computer,\"computer\",NK_TEXT_CENTERED))\n                    file_browser_reload_directory_content(browser, \"/\");\n                nk_group_end(ctx);\n            }\n\n            /* output directory content window */\n            nk_group_begin(ctx, \"Content\", NK_WINDOW_BORDER);\n            {\n                int index = -1;\n                size_t i = 0, j = 0;\n                size_t rows = 0, cols = 0;\n                size_t count = browser->dir_count + browser->file_count;\n\n                /* File icons layout */\n                cols = 2;\n                rows = count / cols;\n                static float ratio2[] = {0.08f, NK_UNDEFINED};\n                nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio2);\n                for (i = 0; i <= rows; i += 1) {\n                    size_t n = j + cols;\n                    for (; j < count && j < n; ++j) {\n                        /* draw one column of icons */\n                        if (j < browser->dir_count) {\n                            /* draw and execute directory buttons */\n                            if (nk_button_image(ctx,media->icons.directory))\n                                index = (int)j;\n\n                            qsort(browser->directories, browser->dir_count, sizeof(char *), cmp_fn);\n                            nk_label(ctx, browser->directories[j], NK_TEXT_LEFT);\n                        } else {\n                            /* draw and execute files buttons */\n                            struct nk_image *icon;\n                            size_t fileIndex = ((size_t)j - browser->dir_count);\n                            icon = media_icon_for_file(media,browser->files[fileIndex]);\n                            if (nk_button_image(ctx, *icon)) {\n                                strncpy(browser->file, browser->directory, MAX_PATH_LEN);\n                                n = strlen(browser->file);\n                                strncpy(browser->file + n, browser->files[fileIndex], MAX_PATH_LEN - n);\n                                ret = 1;\n                            }\n                        }\n                        /* draw one column of labels */\n                        if (j >= browser->dir_count) {\n                            size_t t = j - browser->dir_count;\n                            qsort(browser->files, browser->file_count, sizeof(char *), cmp_fn);\n                            nk_label(ctx,browser->files[t],NK_TEXT_LEFT);\n                        }\n                    }\n                }\n\n                if (index != -1) {\n                    size_t n = strlen(browser->directory);\n                    strncpy(browser->directory + n, browser->directories[index], MAX_PATH_LEN - n);\n                    n = strlen(browser->directory);\n                    if (n < MAX_PATH_LEN - 1) {\n                        browser->directory[n] = '/';\n                        browser->directory[n+1] = '\\0';\n                    }\n                    file_browser_reload_directory_content(browser, browser->directory);\n                }\n                nk_group_end(ctx);\n            }\n\n            nk_layout_row_dynamic(ctx, 30, 5);\n            nk_label(ctx,\"\",NK_TEXT_LEFT);\n            nk_label(ctx,\"\",NK_TEXT_LEFT);\n            nk_label(ctx,\"\",NK_TEXT_LEFT);\n            if(nk_button_label(ctx, \"Cancel\"))\n            {\n                fprintf(stdout, \"File dialog has been closed!\\n\");\n                file_browser_is_open = nk_false;\n            }\n            if(nk_button_label(ctx, \"Open\"))\n                fprintf(stdout, \"Insert routine to open/save the file!\\n\");\n        }\n        nk_end(ctx);\n    }\n    return ret;\n}\n"
  },
  {
    "path": "demo/common/filebrowser/stb_image.h",
    "content": "/* stb_image - v2.28 - public domain image loader - http://nothings.org/stb\n                                  no warranty implied; use at your own risk\n\n   Do this:\n      #define STB_IMAGE_IMPLEMENTATION\n   before you include this file in *one* C or C++ file to create the implementation.\n\n   // i.e. it should look like this:\n   #include ...\n   #include ...\n   #include ...\n   #define STB_IMAGE_IMPLEMENTATION\n   #include \"stb_image.h\"\n\n   You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.\n   And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free\n\n\n   QUICK NOTES:\n      Primarily of interest to game developers and other people who can\n          avoid problematic images and only need the trivial interface\n\n      JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)\n      PNG 1/2/4/8/16-bit-per-channel\n\n      TGA (not sure what subset, if a subset)\n      BMP non-1bpp, non-RLE\n      PSD (composited view only, no extra channels, 8/16 bit-per-channel)\n\n      GIF (*comp always reports as 4-channel)\n      HDR (radiance rgbE format)\n      PIC (Softimage PIC)\n      PNM (PPM and PGM binary only)\n\n      Animated GIF still needs a proper API, but here's one way to do it:\n          http://gist.github.com/urraka/685d9a6340b26b830d49\n\n      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)\n      - decode from arbitrary I/O callbacks\n      - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)\n\n   Full documentation under \"DOCUMENTATION\" below.\n\n\nLICENSE\n\n  See end of file for license information.\n\nRECENT REVISION HISTORY:\n\n      2.28  (2023-01-29) many error fixes, security errors, just tons of stuff\n      2.27  (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes\n      2.26  (2020-07-13) many minor fixes\n      2.25  (2020-02-02) fix warnings\n      2.24  (2020-02-02) fix warnings; thread-local failure_reason and flip_vertically\n      2.23  (2019-08-11) fix clang static analysis warning\n      2.22  (2019-03-04) gif fixes, fix warnings\n      2.21  (2019-02-25) fix typo in comment\n      2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs\n      2.19  (2018-02-11) fix warning\n      2.18  (2018-01-30) fix warnings\n      2.17  (2018-01-29) bugfix, 1-bit BMP, 16-bitness query, fix warnings\n      2.16  (2017-07-23) all functions have 16-bit variants; optimizations; bugfixes\n      2.15  (2017-03-18) fix png-1,2,4; all Imagenet JPGs; no runtime SSE detection on GCC\n      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs\n      2.13  (2016-12-04) experimental 16-bit API, only for PNG so far; fixes\n      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes\n      2.11  (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64\n                         RGB-format JPEG; remove white matting in PSD;\n                         allocate large structures on the stack;\n                         correct channel count for PNG & BMP\n      2.10  (2016-01-22) avoid warning introduced in 2.09\n      2.09  (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED\n\n   See end of file for full revision history.\n\n\n ============================    Contributors    =========================\n\n Image formats                          Extensions, features\n    Sean Barrett (jpeg, png, bmp)          Jetro Lauha (stbi_info)\n    Nicolas Schulz (hdr, psd)              Martin \"SpartanJ\" Golini (stbi_info)\n    Jonathan Dummer (tga)                  James \"moose2000\" Brown (iPhone PNG)\n    Jean-Marc Lienher (gif)                Ben \"Disch\" Wenger (io callbacks)\n    Tom Seddon (pic)                       Omar Cornut (1/2/4-bit PNG)\n    Thatcher Ulrich (psd)                  Nicolas Guillemot (vertical flip)\n    Ken Miller (pgm, ppm)                  Richard Mitton (16-bit PSD)\n    github:urraka (animated gif)           Junggon Kim (PNM comments)\n    Christopher Forseth (animated gif)     Daniel Gibson (16-bit TGA)\n                                           socks-the-fox (16-bit PNG)\n                                           Jeremy Sawicki (handle all ImageNet JPGs)\n Optimizations & bugfixes                  Mikhail Morozov (1-bit BMP)\n    Fabian \"ryg\" Giesen                    Anael Seghezzi (is-16-bit query)\n    Arseny Kapoulkine                      Simon Breuss (16-bit PNM)\n    John-Mark Allen\n    Carmelo J Fdez-Aguera\n\n Bug & warning fixes\n    Marc LeBlanc            David Woo          Guillaume George     Martins Mozeiko\n    Christpher Lloyd        Jerry Jansson      Joseph Thomson       Blazej Dariusz Roszkowski\n    Phil Jordan                                Dave Moore           Roy Eltham\n    Hayaki Saito            Nathan Reed        Won Chun\n    Luke Graham             Johan Duparc       Nick Verigakis       the Horde3D community\n    Thomas Ruf              Ronny Chevalier                         github:rlyeh\n    Janez Zemva             John Bartholomew   Michal Cichon        github:romigrou\n    Jonathan Blow           Ken Hamada         Tero Hanninen        github:svdijk\n    Eugene Golushkov        Laurent Gomila     Cort Stratton        github:snagar\n    Aruelien Pocheville     Sergio Gonzalez    Thibault Reuille     github:Zelex\n    Cass Everitt            Ryamond Barbiero                        github:grim210\n    Paul Du Bois            Engin Manap        Aldo Culquicondor    github:sammyhw\n    Philipp Wiesemann       Dale Weiler        Oriol Ferrer Mesia   github:phprus\n    Josh Tobin              Neil Bickford      Matthew Gregan       github:poppolopoppo\n    Julian Raschke          Gregory Mullen     Christian Floisand   github:darealshinji\n    Baldur Karlsson         Kevin Schmidt      JR Smith             github:Michaelangel007\n                            Brad Weinberger    Matvey Cherevko      github:mosra\n    Luca Sas                Alexander Veselov  Zack Middleton       [reserved]\n    Ryan C. Gordon          [reserved]                              [reserved]\n                     DO NOT ADD YOUR NAME HERE\n\n                     Jacko Dirks\n\n  To add your name to the credits, pick a random blank space in the middle and fill it.\n  80% of merge conflicts on stb PRs are due to people adding their name at the end\n  of the credits.\n*/\n\n#ifndef STBI_INCLUDE_STB_IMAGE_H\n#define STBI_INCLUDE_STB_IMAGE_H\n\n// DOCUMENTATION\n//\n// Limitations:\n//    - no 12-bit-per-channel JPEG\n//    - no JPEGs with arithmetic coding\n//    - GIF always returns *comp=4\n//\n// Basic usage (see HDR discussion below for HDR usage):\n//    int x,y,n;\n//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);\n//    // ... process data if not NULL ...\n//    // ... x = width, y = height, n = # 8-bit components per pixel ...\n//    // ... replace '0' with '1'..'4' to force that many components per pixel\n//    // ... but 'n' will always be the number that it would have been if you said 0\n//    stbi_image_free(data);\n//\n// Standard parameters:\n//    int *x                 -- outputs image width in pixels\n//    int *y                 -- outputs image height in pixels\n//    int *channels_in_file  -- outputs # of image components in image file\n//    int desired_channels   -- if non-zero, # of image components requested in result\n//\n// The return value from an image loader is an 'unsigned char *' which points\n// to the pixel data, or NULL on an allocation failure or if the image is\n// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,\n// with each pixel consisting of N interleaved 8-bit components; the first\n// pixel pointed to is top-left-most in the image. There is no padding between\n// image scanlines or between pixels, regardless of format. The number of\n// components N is 'desired_channels' if desired_channels is non-zero, or\n// *channels_in_file otherwise. If desired_channels is non-zero,\n// *channels_in_file has the number of components that _would_ have been\n// output otherwise. E.g. if you set desired_channels to 4, you will always\n// get RGBA output, but you can check *channels_in_file to see if it's trivially\n// opaque because e.g. there were only 3 channels in the source image.\n//\n// An output image with N components has the following components interleaved\n// in this order in each pixel:\n//\n//     N=#comp     components\n//       1           grey\n//       2           grey, alpha\n//       3           red, green, blue\n//       4           red, green, blue, alpha\n//\n// If image loading fails for any reason, the return value will be NULL,\n// and *x, *y, *channels_in_file will be unchanged. The function\n// stbi_failure_reason() can be queried for an extremely brief, end-user\n// unfriendly explanation of why the load failed. Define STBI_NO_FAILURE_STRINGS\n// to avoid compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly\n// more user-friendly ones.\n//\n// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.\n//\n// To query the width, height and component count of an image without having to\n// decode the full file, you can use the stbi_info family of functions:\n//\n//   int x,y,n,ok;\n//   ok = stbi_info(filename, &x, &y, &n);\n//   // returns ok=1 and sets x, y, n if image is a supported format,\n//   // 0 otherwise.\n//\n// Note that stb_image pervasively uses ints in its public API for sizes,\n// including sizes of memory buffers. This is now part of the API and thus\n// hard to change without causing breakage. As a result, the various image\n// loaders all have certain limits on image size; these differ somewhat\n// by format but generally boil down to either just under 2GB or just under\n// 1GB. When the decoded image would be larger than this, stb_image decoding\n// will fail.\n//\n// Additionally, stb_image will reject image files that have any of their\n// dimensions set to a larger value than the configurable STBI_MAX_DIMENSIONS,\n// which defaults to 2**24 = 16777216 pixels. Due to the above memory limit,\n// the only way to have an image with such dimensions load correctly\n// is for it to have a rather extreme aspect ratio. Either way, the\n// assumption here is that such larger images are likely to be malformed\n// or malicious. If you do need to load an image with individual dimensions\n// larger than that, and it still fits in the overall size limit, you can\n// #define STBI_MAX_DIMENSIONS on your own to be something larger.\n//\n// ===========================================================================\n//\n// UNICODE:\n//\n//   If compiling for Windows and you wish to use Unicode filenames, compile\n//   with\n//       #define STBI_WINDOWS_UTF8\n//   and pass utf8-encoded filenames. Call stbi_convert_wchar_to_utf8 to convert\n//   Windows wchar_t filenames to utf8.\n//\n// ===========================================================================\n//\n// Philosophy\n//\n// stb libraries are designed with the following priorities:\n//\n//    1. easy to use\n//    2. easy to maintain\n//    3. good performance\n//\n// Sometimes I let \"good performance\" creep up in priority over \"easy to maintain\",\n// and for best performance I may provide less-easy-to-use APIs that give higher\n// performance, in addition to the easy-to-use ones. Nevertheless, it's important\n// to keep in mind that from the standpoint of you, a client of this library,\n// all you care about is #1 and #3, and stb libraries DO NOT emphasize #3 above all.\n//\n// Some secondary priorities arise directly from the first two, some of which\n// provide more explicit reasons why performance can't be emphasized.\n//\n//    - Portable (\"ease of use\")\n//    - Small source code footprint (\"easy to maintain\")\n//    - No dependencies (\"ease of use\")\n//\n// ===========================================================================\n//\n// I/O callbacks\n//\n// I/O callbacks allow you to read from arbitrary sources, like packaged\n// files or some other source. Data read from callbacks are processed\n// through a small internal buffer (currently 128 bytes) to try to reduce\n// overhead.\n//\n// The three functions you must define are \"read\" (reads some bytes of data),\n// \"skip\" (skips some bytes of data), \"eof\" (reports if the stream is at the end).\n//\n// ===========================================================================\n//\n// SIMD support\n//\n// The JPEG decoder will try to automatically use SIMD kernels on x86 when\n// supported by the compiler. For ARM Neon support, you must explicitly\n// request it.\n//\n// (The old do-it-yourself SIMD API is no longer supported in the current\n// code.)\n//\n// On x86, SSE2 will automatically be used when available based on a run-time\n// test; if not, the generic C versions are used as a fall-back. On ARM targets,\n// the typical path is to have separate builds for NEON and non-NEON devices\n// (at least this is true for iOS and Android). Therefore, the NEON support is\n// toggled by a build flag: define STBI_NEON to get NEON loops.\n//\n// If for some reason you do not want to use any of SIMD code, or if\n// you have issues compiling it, you can disable it entirely by\n// defining STBI_NO_SIMD.\n//\n// ===========================================================================\n//\n// HDR image support   (disable by defining STBI_NO_HDR)\n//\n// stb_image supports loading HDR images in general, and currently the Radiance\n// .HDR file format specifically. You can still load any file through the existing\n// interface; if you attempt to load an HDR file, it will be automatically remapped\n// to LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;\n// both of these constants can be reconfigured through this interface:\n//\n//     stbi_hdr_to_ldr_gamma(2.2f);\n//     stbi_hdr_to_ldr_scale(1.0f);\n//\n// (note, do not use _inverse_ constants; stbi_image will invert them\n// appropriately).\n//\n// Additionally, there is a new, parallel interface for loading files as\n// (linear) floats to preserve the full dynamic range:\n//\n//    float *data = stbi_loadf(filename, &x, &y, &n, 0);\n//\n// If you load LDR images through this interface, those images will\n// be promoted to floating point values, run through the inverse of\n// constants corresponding to the above:\n//\n//     stbi_ldr_to_hdr_scale(1.0f);\n//     stbi_ldr_to_hdr_gamma(2.2f);\n//\n// Finally, given a filename (or an open file or memory block--see header\n// file for details) containing image data, you can query for the \"most\n// appropriate\" interface to use (that is, whether the image is HDR or\n// not), using:\n//\n//     stbi_is_hdr(char *filename);\n//\n// ===========================================================================\n//\n// iPhone PNG support:\n//\n// We optionally support converting iPhone-formatted PNGs (which store\n// premultiplied BGRA) back to RGB, even though they're internally encoded\n// differently. To enable this conversion, call\n// stbi_convert_iphone_png_to_rgb(1).\n//\n// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per\n// pixel to remove any premultiplied alpha *only* if the image file explicitly\n// says there's premultiplied data (currently only happens in iPhone images,\n// and only if iPhone convert-to-rgb processing is on).\n//\n// ===========================================================================\n//\n// ADDITIONAL CONFIGURATION\n//\n//  - You can suppress implementation of any of the decoders to reduce\n//    your code footprint by #defining one or more of the following\n//    symbols before creating the implementation.\n//\n//        STBI_NO_JPEG\n//        STBI_NO_PNG\n//        STBI_NO_BMP\n//        STBI_NO_PSD\n//        STBI_NO_TGA\n//        STBI_NO_GIF\n//        STBI_NO_HDR\n//        STBI_NO_PIC\n//        STBI_NO_PNM   (.ppm and .pgm)\n//\n//  - You can request *only* certain decoders and suppress all other ones\n//    (this will be more forward-compatible, as addition of new decoders\n//    doesn't require you to disable them explicitly):\n//\n//        STBI_ONLY_JPEG\n//        STBI_ONLY_PNG\n//        STBI_ONLY_BMP\n//        STBI_ONLY_PSD\n//        STBI_ONLY_TGA\n//        STBI_ONLY_GIF\n//        STBI_ONLY_HDR\n//        STBI_ONLY_PIC\n//        STBI_ONLY_PNM   (.ppm and .pgm)\n//\n//   - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still\n//     want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB\n//\n//  - If you define STBI_MAX_DIMENSIONS, stb_image will reject images greater\n//    than that size (in either width or height) without further processing.\n//    This is to let programs in the wild set an upper bound to prevent\n//    denial-of-service attacks on untrusted data, as one could generate a\n//    valid image of gigantic dimensions and force stb_image to allocate a\n//    huge block of memory and spend disproportionate time decoding it. By\n//    default this is set to (1 << 24), which is 16777216, but that's still\n//    very big.\n\n#ifndef STBI_NO_STDIO\n#include <stdio.h>\n#endif // STBI_NO_STDIO\n\n#define STBI_VERSION 1\n\nenum\n{\n   STBI_default = 0, // only used for desired_channels\n\n   STBI_grey       = 1,\n   STBI_grey_alpha = 2,\n   STBI_rgb        = 3,\n   STBI_rgb_alpha  = 4\n};\n\n#include <stdlib.h>\ntypedef unsigned char stbi_uc;\ntypedef unsigned short stbi_us;\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef STBIDEF\n#ifdef STB_IMAGE_STATIC\n#define STBIDEF static\n#else\n#define STBIDEF extern\n#endif\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// PRIMARY API - works on images of any type\n//\n\n//\n// load image by filename, open file, or memory buffer\n//\n\ntypedef struct\n{\n   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read\n   void     (*skip)  (void *user,int n);                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative\n   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data\n} stbi_io_callbacks;\n\n////////////////////////////////////\n//\n// 8-bits-per-channel interface\n//\n\nSTBIDEF stbi_uc *stbi_load_from_memory   (stbi_uc           const *buffer, int len   , int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk  , void *user, int *x, int *y, int *channels_in_file, int desired_channels);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF stbi_uc *stbi_load            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_uc *stbi_load_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);\n// for stbi_load_from_file, file pointer is left pointing immediately after image\n#endif\n\n#ifndef STBI_NO_GIF\nSTBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp);\n#endif\n\n#ifdef STBI_WINDOWS_UTF8\nSTBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);\n#endif\n\n////////////////////////////////////\n//\n// 16-bits-per-channel interface\n//\n\nSTBIDEF stbi_us *stbi_load_16_from_memory   (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF stbi_us *stbi_load_16          (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);\nSTBIDEF stbi_us *stbi_load_from_file_16(FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);\n#endif\n\n////////////////////////////////////\n//\n// float-per-channel interface\n//\n#ifndef STBI_NO_LINEAR\n   STBIDEF float *stbi_loadf_from_memory     (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);\n   STBIDEF float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y,  int *channels_in_file, int desired_channels);\n\n   #ifndef STBI_NO_STDIO\n   STBIDEF float *stbi_loadf            (char const *filename, int *x, int *y, int *channels_in_file, int desired_channels);\n   STBIDEF float *stbi_loadf_from_file  (FILE *f, int *x, int *y, int *channels_in_file, int desired_channels);\n   #endif\n#endif\n\n#ifndef STBI_NO_HDR\n   STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma);\n   STBIDEF void   stbi_hdr_to_ldr_scale(float scale);\n#endif // STBI_NO_HDR\n\n#ifndef STBI_NO_LINEAR\n   STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma);\n   STBIDEF void   stbi_ldr_to_hdr_scale(float scale);\n#endif // STBI_NO_LINEAR\n\n// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR\nSTBIDEF int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);\nSTBIDEF int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_is_hdr          (char const *filename);\nSTBIDEF int      stbi_is_hdr_from_file(FILE *f);\n#endif // STBI_NO_STDIO\n\n\n// get a VERY brief reason for failure\n// on most compilers (and ALL modern mainstream compilers) this is threadsafe\nSTBIDEF const char *stbi_failure_reason  (void);\n\n// free the loaded image -- this is just free()\nSTBIDEF void     stbi_image_free      (void *retval_from_stbi_load);\n\n// get image dimensions & components without fully decoding\nSTBIDEF int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);\nSTBIDEF int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);\nSTBIDEF int      stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);\nSTBIDEF int      stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_info               (char const *filename,     int *x, int *y, int *comp);\nSTBIDEF int      stbi_info_from_file     (FILE *f,                  int *x, int *y, int *comp);\nSTBIDEF int      stbi_is_16_bit          (char const *filename);\nSTBIDEF int      stbi_is_16_bit_from_file(FILE *f);\n#endif\n\n\n\n// for image formats that explicitly notate that they have premultiplied alpha,\n// we just return the colors as stored in the file. set this flag to force\n// unpremultiplication. results are undefined if the unpremultiply overflow.\nSTBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);\n\n// indicate whether we should process iphone images back to canonical format,\n// or just pass them through \"as-is\"\nSTBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);\n\n// flip the image vertically, so the first pixel in the output array is the bottom left\nSTBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);\n\n// as above, but only applies to images loaded on the thread that calls the function\n// this function is only available if your compiler supports thread-local variables;\n// calling it will fail to link if your compiler doesn't\nSTBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);\nSTBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);\nSTBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);\n\n// ZLIB client - used by PNG, available for other purposes\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);\nSTBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);\nSTBIDEF int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);\n\nSTBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);\nSTBIDEF int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);\n\n\n#ifdef __cplusplus\n}\n#endif\n\n//\n//\n////   end header file   /////////////////////////////////////////////////////\n#endif // STBI_INCLUDE_STB_IMAGE_H\n\n#ifdef STB_IMAGE_IMPLEMENTATION\n\n#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \\\n  || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \\\n  || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \\\n  || defined(STBI_ONLY_ZLIB)\n   #ifndef STBI_ONLY_JPEG\n   #define STBI_NO_JPEG\n   #endif\n   #ifndef STBI_ONLY_PNG\n   #define STBI_NO_PNG\n   #endif\n   #ifndef STBI_ONLY_BMP\n   #define STBI_NO_BMP\n   #endif\n   #ifndef STBI_ONLY_PSD\n   #define STBI_NO_PSD\n   #endif\n   #ifndef STBI_ONLY_TGA\n   #define STBI_NO_TGA\n   #endif\n   #ifndef STBI_ONLY_GIF\n   #define STBI_NO_GIF\n   #endif\n   #ifndef STBI_ONLY_HDR\n   #define STBI_NO_HDR\n   #endif\n   #ifndef STBI_ONLY_PIC\n   #define STBI_NO_PIC\n   #endif\n   #ifndef STBI_ONLY_PNM\n   #define STBI_NO_PNM\n   #endif\n#endif\n\n#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)\n#define STBI_NO_ZLIB\n#endif\n\n\n#include <stdarg.h>\n#include <stddef.h> // ptrdiff_t on osx\n#include <stdlib.h>\n#include <string.h>\n#include <limits.h>\n\n#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)\n#include <math.h>  // ldexp, pow\n#endif\n\n#ifndef STBI_NO_STDIO\n#include <stdio.h>\n#endif\n\n#ifndef STBI_ASSERT\n#include <assert.h>\n#define STBI_ASSERT(x) assert(x)\n#endif\n\n#ifdef __cplusplus\n#define STBI_EXTERN extern \"C\"\n#else\n#define STBI_EXTERN extern\n#endif\n\n\n#ifndef _MSC_VER\n   #ifdef __cplusplus\n   #define stbi_inline inline\n   #else\n   #define stbi_inline\n   #endif\n#else\n   #define stbi_inline __forceinline\n#endif\n\n#ifndef STBI_NO_THREAD_LOCALS\n   #if defined(__cplusplus) &&  __cplusplus >= 201103L\n      #define STBI_THREAD_LOCAL       thread_local\n   #elif defined(__GNUC__) && __GNUC__ < 5\n      #define STBI_THREAD_LOCAL       __thread\n   #elif defined(_MSC_VER)\n      #define STBI_THREAD_LOCAL       __declspec(thread)\n   #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)\n      #define STBI_THREAD_LOCAL       _Thread_local\n   #endif\n\n   #ifndef STBI_THREAD_LOCAL\n      #if defined(__GNUC__)\n        #define STBI_THREAD_LOCAL       __thread\n      #endif\n   #endif\n#endif\n\n#if defined(_MSC_VER) || defined(__SYMBIAN32__)\ntypedef unsigned short stbi__uint16;\ntypedef   signed short stbi__int16;\ntypedef unsigned int   stbi__uint32;\ntypedef   signed int   stbi__int32;\n#else\n#include <stdint.h>\ntypedef uint16_t stbi__uint16;\ntypedef int16_t  stbi__int16;\ntypedef uint32_t stbi__uint32;\ntypedef int32_t  stbi__int32;\n#endif\n\n// should produce compiler error if size is wrong\ntypedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];\n\n#ifdef _MSC_VER\n#define STBI_NOTUSED(v)  (void)(v)\n#else\n#define STBI_NOTUSED(v)  (void)sizeof(v)\n#endif\n\n#ifdef _MSC_VER\n#define STBI_HAS_LROTL\n#endif\n\n#ifdef STBI_HAS_LROTL\n   #define stbi_lrot(x,y)  _lrotl(x,y)\n#else\n   #define stbi_lrot(x,y)  (((x) << (y)) | ((x) >> (-(y) & 31)))\n#endif\n\n#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))\n// ok\n#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)\n// ok\n#else\n#error \"Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED).\"\n#endif\n\n#ifndef STBI_MALLOC\n#define STBI_MALLOC(sz)           malloc(sz)\n#define STBI_REALLOC(p,newsz)     realloc(p,newsz)\n#define STBI_FREE(p)              free(p)\n#endif\n\n#ifndef STBI_REALLOC_SIZED\n#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)\n#endif\n\n// x86/x64 detection\n#if defined(__x86_64__) || defined(_M_X64)\n#define STBI__X64_TARGET\n#elif defined(__i386) || defined(_M_IX86)\n#define STBI__X86_TARGET\n#endif\n\n#if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)\n// gcc doesn't support sse2 intrinsics unless you compile with -msse2,\n// which in turn means it gets to use SSE2 everywhere. This is unfortunate,\n// but previous attempts to provide the SSE2 functions with runtime\n// detection caused numerous issues. The way architecture extensions are\n// exposed in GCC/Clang is, sadly, not really suited for one-file libs.\n// New behavior: if compiled with -msse2, we use SSE2 without any\n// detection; if not, we don't use it at all.\n#define STBI_NO_SIMD\n#endif\n\n#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)\n// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET\n//\n// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the\n// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.\n// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not\n// simultaneously enabling \"-mstackrealign\".\n//\n// See https://github.com/nothings/stb/issues/81 for more information.\n//\n// So default to no SSE2 on 32-bit MinGW. If you've read this far and added\n// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.\n#define STBI_NO_SIMD\n#endif\n\n#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))\n#define STBI_SSE2\n#include <emmintrin.h>\n\n#ifdef _MSC_VER\n\n#if _MSC_VER >= 1400  // not VC6\n#include <intrin.h> // __cpuid\nstatic int stbi__cpuid3(void)\n{\n   int info[4];\n   __cpuid(info,1);\n   return info[3];\n}\n#else\nstatic int stbi__cpuid3(void)\n{\n   int res;\n   __asm {\n      mov  eax,1\n      cpuid\n      mov  res,edx\n   }\n   return res;\n}\n#endif\n\n#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name\n\n#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)\nstatic int stbi__sse2_available(void)\n{\n   int info3 = stbi__cpuid3();\n   return ((info3 >> 26) & 1) != 0;\n}\n#endif\n\n#else // assume GCC-style if not VC++\n#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))\n\n#if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)\nstatic int stbi__sse2_available(void)\n{\n   // If we're even attempting to compile this on GCC/Clang, that means\n   // -msse2 is on, which means the compiler is allowed to use SSE2\n   // instructions at will, and so are we.\n   return 1;\n}\n#endif\n\n#endif\n#endif\n\n// ARM NEON\n#if defined(STBI_NO_SIMD) && defined(STBI_NEON)\n#undef STBI_NEON\n#endif\n\n#ifdef STBI_NEON\n#include <arm_neon.h>\n#ifdef _MSC_VER\n#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name\n#else\n#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))\n#endif\n#endif\n\n#ifndef STBI_SIMD_ALIGN\n#define STBI_SIMD_ALIGN(type, name) type name\n#endif\n\n#ifndef STBI_MAX_DIMENSIONS\n#define STBI_MAX_DIMENSIONS (1 << 24)\n#endif\n\n///////////////////////////////////////////////\n//\n//  stbi__context struct and start_xxx functions\n\n// stbi__context structure is our basic context used by all images, so it\n// contains all the IO context, plus some basic image information\ntypedef struct\n{\n   stbi__uint32 img_x, img_y;\n   int img_n, img_out_n;\n\n   stbi_io_callbacks io;\n   void *io_user_data;\n\n   int read_from_callbacks;\n   int buflen;\n   stbi_uc buffer_start[128];\n   int callback_already_read;\n\n   stbi_uc *img_buffer, *img_buffer_end;\n   stbi_uc *img_buffer_original, *img_buffer_original_end;\n} stbi__context;\n\n\nstatic void stbi__refill_buffer(stbi__context *s);\n\n// initialize a memory-decode context\nstatic void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)\n{\n   s->io.read = NULL;\n   s->read_from_callbacks = 0;\n   s->callback_already_read = 0;\n   s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;\n   s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;\n}\n\n// initialize a callback-based context\nstatic void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)\n{\n   s->io = *c;\n   s->io_user_data = user;\n   s->buflen = sizeof(s->buffer_start);\n   s->read_from_callbacks = 1;\n   s->callback_already_read = 0;\n   s->img_buffer = s->img_buffer_original = s->buffer_start;\n   stbi__refill_buffer(s);\n   s->img_buffer_original_end = s->img_buffer_end;\n}\n\n#ifndef STBI_NO_STDIO\n\nstatic int stbi__stdio_read(void *user, char *data, int size)\n{\n   return (int) fread(data,1,size,(FILE*) user);\n}\n\nstatic void stbi__stdio_skip(void *user, int n)\n{\n   int ch;\n   fseek((FILE*) user, n, SEEK_CUR);\n   ch = fgetc((FILE*) user);  /* have to read a byte to reset feof()'s flag */\n   if (ch != EOF) {\n      ungetc(ch, (FILE *) user);  /* push byte back onto stream if valid. */\n   }\n}\n\nstatic int stbi__stdio_eof(void *user)\n{\n   return feof((FILE*) user) || ferror((FILE *) user);\n}\n\nstatic stbi_io_callbacks stbi__stdio_callbacks =\n{\n   stbi__stdio_read,\n   stbi__stdio_skip,\n   stbi__stdio_eof,\n};\n\nstatic void stbi__start_file(stbi__context *s, FILE *f)\n{\n   stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);\n}\n\n//static void stop_file(stbi__context *s) { }\n\n#endif // !STBI_NO_STDIO\n\nstatic void stbi__rewind(stbi__context *s)\n{\n   // conceptually rewind SHOULD rewind to the beginning of the stream,\n   // but we just rewind to the beginning of the initial buffer, because\n   // we only use it after doing 'test', which only ever looks at at most 92 bytes\n   s->img_buffer = s->img_buffer_original;\n   s->img_buffer_end = s->img_buffer_original_end;\n}\n\nenum\n{\n   STBI_ORDER_RGB,\n   STBI_ORDER_BGR\n};\n\ntypedef struct\n{\n   int bits_per_channel;\n   int num_channels;\n   int channel_order;\n} stbi__result_info;\n\n#ifndef STBI_NO_JPEG\nstatic int      stbi__jpeg_test(stbi__context *s);\nstatic void    *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PNG\nstatic int      stbi__png_test(stbi__context *s);\nstatic void    *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__png_info(stbi__context *s, int *x, int *y, int *comp);\nstatic int      stbi__png_is16(stbi__context *s);\n#endif\n\n#ifndef STBI_NO_BMP\nstatic int      stbi__bmp_test(stbi__context *s);\nstatic void    *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_TGA\nstatic int      stbi__tga_test(stbi__context *s);\nstatic void    *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PSD\nstatic int      stbi__psd_test(stbi__context *s);\nstatic void    *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc);\nstatic int      stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);\nstatic int      stbi__psd_is16(stbi__context *s);\n#endif\n\n#ifndef STBI_NO_HDR\nstatic int      stbi__hdr_test(stbi__context *s);\nstatic float   *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PIC\nstatic int      stbi__pic_test(stbi__context *s);\nstatic void    *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_GIF\nstatic int      stbi__gif_test(stbi__context *s);\nstatic void    *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic void    *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp);\nstatic int      stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PNM\nstatic int      stbi__pnm_test(stbi__context *s);\nstatic void    *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);\nstatic int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);\nstatic int      stbi__pnm_is16(stbi__context *s);\n#endif\n\nstatic\n#ifdef STBI_THREAD_LOCAL\nSTBI_THREAD_LOCAL\n#endif\nconst char *stbi__g_failure_reason;\n\nSTBIDEF const char *stbi_failure_reason(void)\n{\n   return stbi__g_failure_reason;\n}\n\n#ifndef STBI_NO_FAILURE_STRINGS\nstatic int stbi__err(const char *str)\n{\n   stbi__g_failure_reason = str;\n   return 0;\n}\n#endif\n\nstatic void *stbi__malloc(size_t size)\n{\n    return STBI_MALLOC(size);\n}\n\n// stb_image uses ints pervasively, including for offset calculations.\n// therefore the largest decoded image size we can support with the\n// current code, even on 64-bit targets, is INT_MAX. this is not a\n// significant limitation for the intended use case.\n//\n// we do, however, need to make sure our size calculations don't\n// overflow. hence a few helper functions for size calculations that\n// multiply integers together, making sure that they're non-negative\n// and no overflow occurs.\n\n// return 1 if the sum is valid, 0 on overflow.\n// negative terms are considered invalid.\nstatic int stbi__addsizes_valid(int a, int b)\n{\n   if (b < 0) return 0;\n   // now 0 <= b <= INT_MAX, hence also\n   // 0 <= INT_MAX - b <= INTMAX.\n   // And \"a + b <= INT_MAX\" (which might overflow) is the\n   // same as a <= INT_MAX - b (no overflow)\n   return a <= INT_MAX - b;\n}\n\n// returns 1 if the product is valid, 0 on overflow.\n// negative factors are considered invalid.\nstatic int stbi__mul2sizes_valid(int a, int b)\n{\n   if (a < 0 || b < 0) return 0;\n   if (b == 0) return 1; // mul-by-0 is always safe\n   // portable way to check for no overflows in a*b\n   return a <= INT_MAX/b;\n}\n\n#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)\n// returns 1 if \"a*b + add\" has no negative terms/factors and doesn't overflow\nstatic int stbi__mad2sizes_valid(int a, int b, int add)\n{\n   return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);\n}\n#endif\n\n// returns 1 if \"a*b*c + add\" has no negative terms/factors and doesn't overflow\nstatic int stbi__mad3sizes_valid(int a, int b, int c, int add)\n{\n   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&\n      stbi__addsizes_valid(a*b*c, add);\n}\n\n// returns 1 if \"a*b*c*d + add\" has no negative terms/factors and doesn't overflow\n#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)\nstatic int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)\n{\n   return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&\n      stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);\n}\n#endif\n\n#if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)\n// mallocs with size overflow checking\nstatic void *stbi__malloc_mad2(int a, int b, int add)\n{\n   if (!stbi__mad2sizes_valid(a, b, add)) return NULL;\n   return stbi__malloc(a*b + add);\n}\n#endif\n\nstatic void *stbi__malloc_mad3(int a, int b, int c, int add)\n{\n   if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;\n   return stbi__malloc(a*b*c + add);\n}\n\n#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)\nstatic void *stbi__malloc_mad4(int a, int b, int c, int d, int add)\n{\n   if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;\n   return stbi__malloc(a*b*c*d + add);\n}\n#endif\n\n// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow.\nstatic int stbi__addints_valid(int a, int b)\n{\n   if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow\n   if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0.\n   return a <= INT_MAX - b;\n}\n\n// returns 1 if the product of two signed shorts is valid, 0 on overflow.\nstatic int stbi__mul2shorts_valid(short a, short b)\n{\n   if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow\n   if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid\n   if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN\n   return a >= SHRT_MIN / b;\n}\n\n// stbi__err - error\n// stbi__errpf - error returning pointer to float\n// stbi__errpuc - error returning pointer to unsigned char\n\n#ifdef STBI_NO_FAILURE_STRINGS\n   #define stbi__err(x,y)  0\n#elif defined(STBI_FAILURE_USERMSG)\n   #define stbi__err(x,y)  stbi__err(y)\n#else\n   #define stbi__err(x,y)  stbi__err(x)\n#endif\n\n#define stbi__errpf(x,y)   ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))\n#define stbi__errpuc(x,y)  ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))\n\nSTBIDEF void stbi_image_free(void *retval_from_stbi_load)\n{\n   STBI_FREE(retval_from_stbi_load);\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);\n#endif\n\n#ifndef STBI_NO_HDR\nstatic stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp);\n#endif\n\nstatic int stbi__vertically_flip_on_load_global = 0;\n\nSTBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)\n{\n   stbi__vertically_flip_on_load_global = flag_true_if_should_flip;\n}\n\n#ifndef STBI_THREAD_LOCAL\n#define stbi__vertically_flip_on_load  stbi__vertically_flip_on_load_global\n#else\nstatic STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set;\n\nSTBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip)\n{\n   stbi__vertically_flip_on_load_local = flag_true_if_should_flip;\n   stbi__vertically_flip_on_load_set = 1;\n}\n\n#define stbi__vertically_flip_on_load  (stbi__vertically_flip_on_load_set       \\\n                                         ? stbi__vertically_flip_on_load_local  \\\n                                         : stbi__vertically_flip_on_load_global)\n#endif // STBI_THREAD_LOCAL\n\nstatic void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)\n{\n   memset(ri, 0, sizeof(*ri)); // make sure it's initialized if we add new fields\n   ri->bits_per_channel = 8; // default is 8 so most paths don't have to be changed\n   ri->channel_order = STBI_ORDER_RGB; // all current input & output are this, but this is here so we can add BGR order\n   ri->num_channels = 0;\n\n   // test the formats with a very explicit header first (at least a FOURCC\n   // or distinctive magic number first)\n   #ifndef STBI_NO_PNG\n   if (stbi__png_test(s))  return stbi__png_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_BMP\n   if (stbi__bmp_test(s))  return stbi__bmp_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_GIF\n   if (stbi__gif_test(s))  return stbi__gif_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_test(s))  return stbi__psd_load(s,x,y,comp,req_comp, ri, bpc);\n   #else\n   STBI_NOTUSED(bpc);\n   #endif\n   #ifndef STBI_NO_PIC\n   if (stbi__pic_test(s))  return stbi__pic_load(s,x,y,comp,req_comp, ri);\n   #endif\n\n   // then the formats that can end up attempting to load with just 1 or 2\n   // bytes matching expectations; these are prone to false positives, so\n   // try them later\n   #ifndef STBI_NO_JPEG\n   if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp, ri);\n   #endif\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_test(s))  return stbi__pnm_load(s,x,y,comp,req_comp, ri);\n   #endif\n\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_test(s)) {\n      float *hdr = stbi__hdr_load(s, x,y,comp,req_comp, ri);\n      return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);\n   }\n   #endif\n\n   #ifndef STBI_NO_TGA\n   // test tga last because it's a crappy test!\n   if (stbi__tga_test(s))\n      return stbi__tga_load(s,x,y,comp,req_comp, ri);\n   #endif\n\n   return stbi__errpuc(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nstatic stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels)\n{\n   int i;\n   int img_len = w * h * channels;\n   stbi_uc *reduced;\n\n   reduced = (stbi_uc *) stbi__malloc(img_len);\n   if (reduced == NULL) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   for (i = 0; i < img_len; ++i)\n      reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is sufficient approx of 16->8 bit scaling\n\n   STBI_FREE(orig);\n   return reduced;\n}\n\nstatic stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels)\n{\n   int i;\n   int img_len = w * h * channels;\n   stbi__uint16 *enlarged;\n\n   enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);\n   if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   for (i = 0; i < img_len; ++i)\n      enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]); // replicate to high and low byte, maps 0->0, 255->0xffff\n\n   STBI_FREE(orig);\n   return enlarged;\n}\n\nstatic void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)\n{\n   int row;\n   size_t bytes_per_row = (size_t)w * bytes_per_pixel;\n   stbi_uc temp[2048];\n   stbi_uc *bytes = (stbi_uc *)image;\n\n   for (row = 0; row < (h>>1); row++) {\n      stbi_uc *row0 = bytes + row*bytes_per_row;\n      stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row;\n      // swap row0 with row1\n      size_t bytes_left = bytes_per_row;\n      while (bytes_left) {\n         size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);\n         memcpy(temp, row0, bytes_copy);\n         memcpy(row0, row1, bytes_copy);\n         memcpy(row1, temp, bytes_copy);\n         row0 += bytes_copy;\n         row1 += bytes_copy;\n         bytes_left -= bytes_copy;\n      }\n   }\n}\n\n#ifndef STBI_NO_GIF\nstatic void stbi__vertical_flip_slices(void *image, int w, int h, int z, int bytes_per_pixel)\n{\n   int slice;\n   int slice_size = w * h * bytes_per_pixel;\n\n   stbi_uc *bytes = (stbi_uc *)image;\n   for (slice = 0; slice < z; ++slice) {\n      stbi__vertical_flip(bytes, w, h, bytes_per_pixel);\n      bytes += slice_size;\n   }\n}\n#endif\n\nstatic unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__result_info ri;\n   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);\n\n   if (result == NULL)\n      return NULL;\n\n   // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.\n   STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);\n\n   if (ri.bits_per_channel != 8) {\n      result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);\n      ri.bits_per_channel = 8;\n   }\n\n   // @TODO: move stbi__convert_format to here\n\n   if (stbi__vertically_flip_on_load) {\n      int channels = req_comp ? req_comp : *comp;\n      stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));\n   }\n\n   return (unsigned char *) result;\n}\n\nstatic stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__result_info ri;\n   void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);\n\n   if (result == NULL)\n      return NULL;\n\n   // it is the responsibility of the loaders to make sure we get either 8 or 16 bit.\n   STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);\n\n   if (ri.bits_per_channel != 16) {\n      result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);\n      ri.bits_per_channel = 16;\n   }\n\n   // @TODO: move stbi__convert_format16 to here\n   // @TODO: special case RGB-to-Y (and RGBA-to-YA) for 8-bit-to-16-bit case to keep more precision\n\n   if (stbi__vertically_flip_on_load) {\n      int channels = req_comp ? req_comp : *comp;\n      stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));\n   }\n\n   return (stbi__uint16 *) result;\n}\n\n#if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR)\nstatic void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)\n{\n   if (stbi__vertically_flip_on_load && result != NULL) {\n      int channels = req_comp ? req_comp : *comp;\n      stbi__vertical_flip(result, *x, *y, channels * sizeof(float));\n   }\n}\n#endif\n\n#ifndef STBI_NO_STDIO\n\n#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)\nSTBI_EXTERN __declspec(dllimport) int __stdcall MultiByteToWideChar(unsigned int cp, unsigned long flags, const char *str, int cbmb, wchar_t *widestr, int cchwide);\nSTBI_EXTERN __declspec(dllimport) int __stdcall WideCharToMultiByte(unsigned int cp, unsigned long flags, const wchar_t *widestr, int cchwide, char *str, int cbmb, const char *defchar, int *used_default);\n#endif\n\n#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)\nSTBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input)\n{\n\treturn WideCharToMultiByte(65001 /* UTF8 */, 0, input, -1, buffer, (int) bufferlen, NULL, NULL);\n}\n#endif\n\nstatic FILE *stbi__fopen(char const *filename, char const *mode)\n{\n   FILE *f;\n#if defined(_WIN32) && defined(STBI_WINDOWS_UTF8)\n   wchar_t wMode[64];\n   wchar_t wFilename[1024];\n\tif (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, filename, -1, wFilename, sizeof(wFilename)/sizeof(*wFilename)))\n      return 0;\n\n\tif (0 == MultiByteToWideChar(65001 /* UTF8 */, 0, mode, -1, wMode, sizeof(wMode)/sizeof(*wMode)))\n      return 0;\n\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n\tif (0 != _wfopen_s(&f, wFilename, wMode))\n\t\tf = 0;\n#else\n   f = _wfopen(wFilename, wMode);\n#endif\n\n#elif defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != fopen_s(&f, filename, mode))\n      f=0;\n#else\n   f = fopen(filename, mode);\n#endif\n   return f;\n}\n\n\nSTBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   unsigned char *result;\n   if (!f) return stbi__errpuc(\"can't fopen\", \"Unable to open file\");\n   result = stbi_load_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\nSTBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   unsigned char *result;\n   stbi__context s;\n   stbi__start_file(&s,f);\n   result = stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);\n   if (result) {\n      // need to 'unget' all the characters in the IO buffer\n      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);\n   }\n   return result;\n}\n\nSTBIDEF stbi__uint16 *stbi_load_from_file_16(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__uint16 *result;\n   stbi__context s;\n   stbi__start_file(&s,f);\n   result = stbi__load_and_postprocess_16bit(&s,x,y,comp,req_comp);\n   if (result) {\n      // need to 'unget' all the characters in the IO buffer\n      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);\n   }\n   return result;\n}\n\nSTBIDEF stbi_us *stbi_load_16(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   stbi__uint16 *result;\n   if (!f) return (stbi_us *) stbi__errpuc(\"can't fopen\", \"Unable to open file\");\n   result = stbi_load_from_file_16(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\n\n#endif //!STBI_NO_STDIO\n\nSTBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);\n}\n\nSTBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user);\n   return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);\n}\n\nSTBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);\n}\n\nSTBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);\n}\n\n#ifndef STBI_NO_GIF\nSTBIDEF stbi_uc *stbi_load_gif_from_memory(stbi_uc const *buffer, int len, int **delays, int *x, int *y, int *z, int *comp, int req_comp)\n{\n   unsigned char *result;\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n\n   result = (unsigned char*) stbi__load_gif_main(&s, delays, x, y, z, comp, req_comp);\n   if (stbi__vertically_flip_on_load) {\n      stbi__vertical_flip_slices( result, *x, *y, *z, *comp );\n   }\n\n   return result;\n}\n#endif\n\n#ifndef STBI_NO_LINEAR\nstatic float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   unsigned char *data;\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_test(s)) {\n      stbi__result_info ri;\n      float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp, &ri);\n      if (hdr_data)\n         stbi__float_postprocess(hdr_data,x,y,comp,req_comp);\n      return hdr_data;\n   }\n   #endif\n   data = stbi__load_and_postprocess_8bit(s, x, y, comp, req_comp);\n   if (data)\n      return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);\n   return stbi__errpf(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nSTBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n\nSTBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   float *result;\n   FILE *f = stbi__fopen(filename, \"rb\");\n   if (!f) return stbi__errpf(\"can't fopen\", \"Unable to open file\");\n   result = stbi_loadf_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\nSTBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_file(&s,f);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n#endif // !STBI_NO_STDIO\n\n#endif // !STBI_NO_LINEAR\n\n// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is\n// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always\n// reports false!\n\nSTBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)\n{\n   #ifndef STBI_NO_HDR\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__hdr_test(&s);\n   #else\n   STBI_NOTUSED(buffer);\n   STBI_NOTUSED(len);\n   return 0;\n   #endif\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_is_hdr          (char const *filename)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   int result=0;\n   if (f) {\n      result = stbi_is_hdr_from_file(f);\n      fclose(f);\n   }\n   return result;\n}\n\nSTBIDEF int stbi_is_hdr_from_file(FILE *f)\n{\n   #ifndef STBI_NO_HDR\n   long pos = ftell(f);\n   int res;\n   stbi__context s;\n   stbi__start_file(&s,f);\n   res = stbi__hdr_test(&s);\n   fseek(f, pos, SEEK_SET);\n   return res;\n   #else\n   STBI_NOTUSED(f);\n   return 0;\n   #endif\n}\n#endif // !STBI_NO_STDIO\n\nSTBIDEF int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)\n{\n   #ifndef STBI_NO_HDR\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__hdr_test(&s);\n   #else\n   STBI_NOTUSED(clbk);\n   STBI_NOTUSED(user);\n   return 0;\n   #endif\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;\n\nSTBIDEF void   stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }\nSTBIDEF void   stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }\n#endif\n\nstatic float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;\n\nSTBIDEF void   stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }\nSTBIDEF void   stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Common code used by all image loaders\n//\n\nenum\n{\n   STBI__SCAN_load=0,\n   STBI__SCAN_type,\n   STBI__SCAN_header\n};\n\nstatic void stbi__refill_buffer(stbi__context *s)\n{\n   int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);\n   s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original);\n   if (n == 0) {\n      // at end of file, treat same as if from memory, but need to handle case\n      // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file\n      s->read_from_callbacks = 0;\n      s->img_buffer = s->buffer_start;\n      s->img_buffer_end = s->buffer_start+1;\n      *s->img_buffer = 0;\n   } else {\n      s->img_buffer = s->buffer_start;\n      s->img_buffer_end = s->buffer_start + n;\n   }\n}\n\nstbi_inline static stbi_uc stbi__get8(stbi__context *s)\n{\n   if (s->img_buffer < s->img_buffer_end)\n      return *s->img_buffer++;\n   if (s->read_from_callbacks) {\n      stbi__refill_buffer(s);\n      return *s->img_buffer++;\n   }\n   return 0;\n}\n\n#if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)\n// nothing\n#else\nstbi_inline static int stbi__at_eof(stbi__context *s)\n{\n   if (s->io.read) {\n      if (!(s->io.eof)(s->io_user_data)) return 0;\n      // if feof() is true, check if buffer = end\n      // special case: we've only got the special 0 character at the end\n      if (s->read_from_callbacks == 0) return 1;\n   }\n\n   return s->img_buffer >= s->img_buffer_end;\n}\n#endif\n\n#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC)\n// nothing\n#else\nstatic void stbi__skip(stbi__context *s, int n)\n{\n   if (n == 0) return;  // already there!\n   if (n < 0) {\n      s->img_buffer = s->img_buffer_end;\n      return;\n   }\n   if (s->io.read) {\n      int blen = (int) (s->img_buffer_end - s->img_buffer);\n      if (blen < n) {\n         s->img_buffer = s->img_buffer_end;\n         (s->io.skip)(s->io_user_data, n - blen);\n         return;\n      }\n   }\n   s->img_buffer += n;\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM)\n// nothing\n#else\nstatic int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)\n{\n   if (s->io.read) {\n      int blen = (int) (s->img_buffer_end - s->img_buffer);\n      if (blen < n) {\n         int res, count;\n\n         memcpy(buffer, s->img_buffer, blen);\n\n         count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);\n         res = (count == (n-blen));\n         s->img_buffer = s->img_buffer_end;\n         return res;\n      }\n   }\n\n   if (s->img_buffer+n <= s->img_buffer_end) {\n      memcpy(buffer, s->img_buffer, n);\n      s->img_buffer += n;\n      return 1;\n   } else\n      return 0;\n}\n#endif\n\n#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)\n// nothing\n#else\nstatic int stbi__get16be(stbi__context *s)\n{\n   int z = stbi__get8(s);\n   return (z << 8) + stbi__get8(s);\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)\n// nothing\n#else\nstatic stbi__uint32 stbi__get32be(stbi__context *s)\n{\n   stbi__uint32 z = stbi__get16be(s);\n   return (z << 16) + stbi__get16be(s);\n}\n#endif\n\n#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)\n// nothing\n#else\nstatic int stbi__get16le(stbi__context *s)\n{\n   int z = stbi__get8(s);\n   return z + (stbi__get8(s) << 8);\n}\n#endif\n\n#ifndef STBI_NO_BMP\nstatic stbi__uint32 stbi__get32le(stbi__context *s)\n{\n   stbi__uint32 z = stbi__get16le(s);\n   z += (stbi__uint32)stbi__get16le(s) << 16;\n   return z;\n}\n#endif\n\n#define STBI__BYTECAST(x)  ((stbi_uc) ((x) & 255))  // truncate int to byte without warnings\n\n#if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)\n// nothing\n#else\n//////////////////////////////////////////////////////////////////////////////\n//\n//  generic converter from built-in img_n to req_comp\n//    individual types do this automatically as much as possible (e.g. jpeg\n//    does all cases internally since it needs to colorspace convert anyway,\n//    and it never has alpha, so very few cases ). png can automatically\n//    interleave an alpha=255 channel, but falls back to this for other cases\n//\n//  assume data buffer is malloced, so malloc a new one and free that one\n//  only failure mode is malloc failing\n\nstatic stbi_uc stbi__compute_y(int r, int g, int b)\n{\n   return (stbi_uc) (((r*77) + (g*150) +  (29*b)) >> 8);\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)\n// nothing\n#else\nstatic unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)\n{\n   int i,j;\n   unsigned char *good;\n\n   if (req_comp == img_n) return data;\n   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);\n\n   good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);\n   if (good == NULL) {\n      STBI_FREE(data);\n      return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   }\n\n   for (j=0; j < (int) y; ++j) {\n      unsigned char *src  = data + j * x * img_n   ;\n      unsigned char *dest = good + j * x * req_comp;\n\n      #define STBI__COMBO(a,b)  ((a)*8+(b))\n      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)\n      // convert source image with img_n components to one with req_comp components;\n      // avoid switch per pixel, so use switch per scanline and massive macros\n      switch (STBI__COMBO(img_n, req_comp)) {\n         STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255;                                     } break;\n         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;\n         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255;                     } break;\n         STBI__CASE(2,1) { dest[0]=src[0];                                                  } break;\n         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                  } break;\n         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1];                  } break;\n         STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255;        } break;\n         STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255;    } break;\n         STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break;\n         STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];                    } break;\n         default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc(\"unsupported\", \"Unsupported format conversion\");\n      }\n      #undef STBI__CASE\n   }\n\n   STBI_FREE(data);\n   return good;\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)\n// nothing\n#else\nstatic stbi__uint16 stbi__compute_y_16(int r, int g, int b)\n{\n   return (stbi__uint16) (((r*77) + (g*150) +  (29*b)) >> 8);\n}\n#endif\n\n#if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)\n// nothing\n#else\nstatic stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)\n{\n   int i,j;\n   stbi__uint16 *good;\n\n   if (req_comp == img_n) return data;\n   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);\n\n   good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);\n   if (good == NULL) {\n      STBI_FREE(data);\n      return (stbi__uint16 *) stbi__errpuc(\"outofmem\", \"Out of memory\");\n   }\n\n   for (j=0; j < (int) y; ++j) {\n      stbi__uint16 *src  = data + j * x * img_n   ;\n      stbi__uint16 *dest = good + j * x * req_comp;\n\n      #define STBI__COMBO(a,b)  ((a)*8+(b))\n      #define STBI__CASE(a,b)   case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)\n      // convert source image with img_n components to one with req_comp components;\n      // avoid switch per pixel, so use switch per scanline and massive macros\n      switch (STBI__COMBO(img_n, req_comp)) {\n         STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff;                                     } break;\n         STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;\n         STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff;                     } break;\n         STBI__CASE(2,1) { dest[0]=src[0];                                                     } break;\n         STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0];                                     } break;\n         STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1];                     } break;\n         STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff;        } break;\n         STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break;\n         STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]);                   } break;\n         STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break;\n         STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];                       } break;\n         default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc(\"unsupported\", \"Unsupported format conversion\");\n      }\n      #undef STBI__CASE\n   }\n\n   STBI_FREE(data);\n   return good;\n}\n#endif\n\n#ifndef STBI_NO_LINEAR\nstatic float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)\n{\n   int i,k,n;\n   float *output;\n   if (!data) return NULL;\n   output = (float *) stbi__malloc_mad4(x, y, comp, sizeof(float), 0);\n   if (output == NULL) { STBI_FREE(data); return stbi__errpf(\"outofmem\", \"Out of memory\"); }\n   // compute number of non-alpha components\n   if (comp & 1) n = comp; else n = comp-1;\n   for (i=0; i < x*y; ++i) {\n      for (k=0; k < n; ++k) {\n         output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);\n      }\n   }\n   if (n < comp) {\n      for (i=0; i < x*y; ++i) {\n         output[i*comp + n] = data[i*comp + n]/255.0f;\n      }\n   }\n   STBI_FREE(data);\n   return output;\n}\n#endif\n\n#ifndef STBI_NO_HDR\n#define stbi__float2int(x)   ((int) (x))\nstatic stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp)\n{\n   int i,k,n;\n   stbi_uc *output;\n   if (!data) return NULL;\n   output = (stbi_uc *) stbi__malloc_mad3(x, y, comp, 0);\n   if (output == NULL) { STBI_FREE(data); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n   // compute number of non-alpha components\n   if (comp & 1) n = comp; else n = comp-1;\n   for (i=0; i < x*y; ++i) {\n      for (k=0; k < n; ++k) {\n         float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;\n         if (z < 0) z = 0;\n         if (z > 255) z = 255;\n         output[i*comp + k] = (stbi_uc) stbi__float2int(z);\n      }\n      if (k < comp) {\n         float z = data[i*comp+k] * 255 + 0.5f;\n         if (z < 0) z = 0;\n         if (z > 255) z = 255;\n         output[i*comp + k] = (stbi_uc) stbi__float2int(z);\n      }\n   }\n   STBI_FREE(data);\n   return output;\n}\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//  \"baseline\" JPEG/JFIF decoder\n//\n//    simple implementation\n//      - doesn't support delayed output of y-dimension\n//      - simple interface (only one output format: 8-bit interleaved RGB)\n//      - doesn't try to recover corrupt jpegs\n//      - doesn't allow partial loading, loading multiple at once\n//      - still fast on x86 (copying globals into locals doesn't help x86)\n//      - allocates lots of intermediate memory (full size of all components)\n//        - non-interleaved case requires this anyway\n//        - allows good upsampling (see next)\n//    high-quality\n//      - upsampled channels are bilinearly interpolated, even across blocks\n//      - quality integer IDCT derived from IJG's 'slow'\n//    performance\n//      - fast huffman; reasonable integer IDCT\n//      - some SIMD kernels for common paths on targets with SSE2/NEON\n//      - uses a lot of intermediate memory, could cache poorly\n\n#ifndef STBI_NO_JPEG\n\n// huffman decoding acceleration\n#define FAST_BITS   9  // larger handles more cases; smaller stomps less cache\n\ntypedef struct\n{\n   stbi_uc  fast[1 << FAST_BITS];\n   // weirdly, repacking this into AoS is a 10% speed loss, instead of a win\n   stbi__uint16 code[256];\n   stbi_uc  values[256];\n   stbi_uc  size[257];\n   unsigned int maxcode[18];\n   int    delta[17];   // old 'firstsymbol' - old 'firstcode'\n} stbi__huffman;\n\ntypedef struct\n{\n   stbi__context *s;\n   stbi__huffman huff_dc[4];\n   stbi__huffman huff_ac[4];\n   stbi__uint16 dequant[4][64];\n   stbi__int16 fast_ac[4][1 << FAST_BITS];\n\n// sizes for components, interleaved MCUs\n   int img_h_max, img_v_max;\n   int img_mcu_x, img_mcu_y;\n   int img_mcu_w, img_mcu_h;\n\n// definition of jpeg image component\n   struct\n   {\n      int id;\n      int h,v;\n      int tq;\n      int hd,ha;\n      int dc_pred;\n\n      int x,y,w2,h2;\n      stbi_uc *data;\n      void *raw_data, *raw_coeff;\n      stbi_uc *linebuf;\n      short   *coeff;   // progressive only\n      int      coeff_w, coeff_h; // number of 8x8 coefficient blocks\n   } img_comp[4];\n\n   stbi__uint32   code_buffer; // jpeg entropy-coded buffer\n   int            code_bits;   // number of valid bits\n   unsigned char  marker;      // marker seen while filling entropy buffer\n   int            nomore;      // flag if we saw a marker so must stop\n\n   int            progressive;\n   int            spec_start;\n   int            spec_end;\n   int            succ_high;\n   int            succ_low;\n   int            eob_run;\n   int            jfif;\n   int            app14_color_transform; // Adobe APP14 tag\n   int            rgb;\n\n   int scan_n, order[4];\n   int restart_interval, todo;\n\n// kernels\n   void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);\n   void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);\n   stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);\n} stbi__jpeg;\n\nstatic int stbi__build_huffman(stbi__huffman *h, int *count)\n{\n   int i,j,k=0;\n   unsigned int code;\n   // build size list for each symbol (from JPEG spec)\n   for (i=0; i < 16; ++i) {\n      for (j=0; j < count[i]; ++j) {\n         h->size[k++] = (stbi_uc) (i+1);\n         if(k >= 257) return stbi__err(\"bad size list\",\"Corrupt JPEG\");\n      }\n   }\n   h->size[k] = 0;\n\n   // compute actual symbols (from jpeg spec)\n   code = 0;\n   k = 0;\n   for(j=1; j <= 16; ++j) {\n      // compute delta to add to code to compute symbol id\n      h->delta[j] = k - code;\n      if (h->size[k] == j) {\n         while (h->size[k] == j)\n            h->code[k++] = (stbi__uint16) (code++);\n         if (code-1 >= (1u << j)) return stbi__err(\"bad code lengths\",\"Corrupt JPEG\");\n      }\n      // compute largest code + 1 for this size, preshifted as needed later\n      h->maxcode[j] = code << (16-j);\n      code <<= 1;\n   }\n   h->maxcode[j] = 0xffffffff;\n\n   // build non-spec acceleration table; 255 is flag for not-accelerated\n   memset(h->fast, 255, 1 << FAST_BITS);\n   for (i=0; i < k; ++i) {\n      int s = h->size[i];\n      if (s <= FAST_BITS) {\n         int c = h->code[i] << (FAST_BITS-s);\n         int m = 1 << (FAST_BITS-s);\n         for (j=0; j < m; ++j) {\n            h->fast[c+j] = (stbi_uc) i;\n         }\n      }\n   }\n   return 1;\n}\n\n// build a table that decodes both magnitude and value of small ACs in\n// one go.\nstatic void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)\n{\n   int i;\n   for (i=0; i < (1 << FAST_BITS); ++i) {\n      stbi_uc fast = h->fast[i];\n      fast_ac[i] = 0;\n      if (fast < 255) {\n         int rs = h->values[fast];\n         int run = (rs >> 4) & 15;\n         int magbits = rs & 15;\n         int len = h->size[fast];\n\n         if (magbits && len + magbits <= FAST_BITS) {\n            // magnitude code followed by receive_extend code\n            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);\n            int m = 1 << (magbits - 1);\n            if (k < m) k += (~0U << magbits) + 1;\n            // if the result is small enough, we can fit it in fast_ac table\n            if (k >= -128 && k <= 127)\n               fast_ac[i] = (stbi__int16) ((k * 256) + (run * 16) + (len + magbits));\n         }\n      }\n   }\n}\n\nstatic void stbi__grow_buffer_unsafe(stbi__jpeg *j)\n{\n   do {\n      unsigned int b = j->nomore ? 0 : stbi__get8(j->s);\n      if (b == 0xff) {\n         int c = stbi__get8(j->s);\n         while (c == 0xff) c = stbi__get8(j->s); // consume fill bytes\n         if (c != 0) {\n            j->marker = (unsigned char) c;\n            j->nomore = 1;\n            return;\n         }\n      }\n      j->code_buffer |= b << (24 - j->code_bits);\n      j->code_bits += 8;\n   } while (j->code_bits <= 24);\n}\n\n// (1 << n) - 1\nstatic const stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};\n\n// decode a jpeg huffman value from the bitstream\nstbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)\n{\n   unsigned int temp;\n   int c,k;\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n\n   // look at the top FAST_BITS and determine what symbol ID it is,\n   // if the code is <= FAST_BITS\n   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n   k = h->fast[c];\n   if (k < 255) {\n      int s = h->size[k];\n      if (s > j->code_bits)\n         return -1;\n      j->code_buffer <<= s;\n      j->code_bits -= s;\n      return h->values[k];\n   }\n\n   // naive test is to shift the code_buffer down so k bits are\n   // valid, then test against maxcode. To speed this up, we've\n   // preshifted maxcode left so that it has (16-k) 0s at the\n   // end; in other words, regardless of the number of bits, it\n   // wants to be compared against something shifted to have 16;\n   // that way we don't need to shift inside the loop.\n   temp = j->code_buffer >> 16;\n   for (k=FAST_BITS+1 ; ; ++k)\n      if (temp < h->maxcode[k])\n         break;\n   if (k == 17) {\n      // error! code not found\n      j->code_bits -= 16;\n      return -1;\n   }\n\n   if (k > j->code_bits)\n      return -1;\n\n   // convert the huffman code to the symbol id\n   c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];\n   if(c < 0 || c >= 256) // symbol id out of bounds!\n       return -1;\n   STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);\n\n   // convert the id to a symbol\n   j->code_bits -= k;\n   j->code_buffer <<= k;\n   return h->values[c];\n}\n\n// bias[n] = (-1<<n) + 1\nstatic const int stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};\n\n// combined JPEG 'receive' and JPEG 'extend', since baseline\n// always extends everything it receives.\nstbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)\n{\n   unsigned int k;\n   int sgn;\n   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);\n   if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing\n\n   sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative)\n   k = stbi_lrot(j->code_buffer, n);\n   j->code_buffer = k & ~stbi__bmask[n];\n   k &= stbi__bmask[n];\n   j->code_bits -= n;\n   return k + (stbi__jbias[n] & (sgn - 1));\n}\n\n// get some unsigned bits\nstbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)\n{\n   unsigned int k;\n   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);\n   if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing\n   k = stbi_lrot(j->code_buffer, n);\n   j->code_buffer = k & ~stbi__bmask[n];\n   k &= stbi__bmask[n];\n   j->code_bits -= n;\n   return k;\n}\n\nstbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)\n{\n   unsigned int k;\n   if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);\n   if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing\n   k = j->code_buffer;\n   j->code_buffer <<= 1;\n   --j->code_bits;\n   return k & 0x80000000;\n}\n\n// given a value that's at position X in the zigzag stream,\n// where does it appear in the 8x8 matrix coded as row-major?\nstatic const stbi_uc stbi__jpeg_dezigzag[64+15] =\n{\n    0,  1,  8, 16,  9,  2,  3, 10,\n   17, 24, 32, 25, 18, 11,  4,  5,\n   12, 19, 26, 33, 40, 48, 41, 34,\n   27, 20, 13,  6,  7, 14, 21, 28,\n   35, 42, 49, 56, 57, 50, 43, 36,\n   29, 22, 15, 23, 30, 37, 44, 51,\n   58, 59, 52, 45, 38, 31, 39, 46,\n   53, 60, 61, 54, 47, 55, 62, 63,\n   // let corrupt input sample past end\n   63, 63, 63, 63, 63, 63, 63, 63,\n   63, 63, 63, 63, 63, 63, 63\n};\n\n// decode one 64-entry block--\nstatic int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi__uint16 *dequant)\n{\n   int diff,dc,k;\n   int t;\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n   t = stbi__jpeg_huff_decode(j, hdc);\n   if (t < 0 || t > 15) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n\n   // 0 all the ac values now so we can do it 32-bits at a time\n   memset(data,0,64*sizeof(data[0]));\n\n   diff = t ? stbi__extend_receive(j, t) : 0;\n   if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err(\"bad delta\",\"Corrupt JPEG\");\n   dc = j->img_comp[b].dc_pred + diff;\n   j->img_comp[b].dc_pred = dc;\n   if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n   data[0] = (short) (dc * dequant[0]);\n\n   // decode AC components, see JPEG spec\n   k = 1;\n   do {\n      unsigned int zig;\n      int c,r,s;\n      if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n      r = fac[c];\n      if (r) { // fast-AC path\n         k += (r >> 4) & 15; // run\n         s = r & 15; // combined length\n         if (s > j->code_bits) return stbi__err(\"bad huffman code\", \"Combined length longer than code bits available\");\n         j->code_buffer <<= s;\n         j->code_bits -= s;\n         // decode into unzigzag'd location\n         zig = stbi__jpeg_dezigzag[k++];\n         data[zig] = (short) ((r >> 8) * dequant[zig]);\n      } else {\n         int rs = stbi__jpeg_huff_decode(j, hac);\n         if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n         s = rs & 15;\n         r = rs >> 4;\n         if (s == 0) {\n            if (rs != 0xf0) break; // end block\n            k += 16;\n         } else {\n            k += r;\n            // decode into unzigzag'd location\n            zig = stbi__jpeg_dezigzag[k++];\n            data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);\n         }\n      }\n   } while (k < 64);\n   return 1;\n}\n\nstatic int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)\n{\n   int diff,dc;\n   int t;\n   if (j->spec_end != 0) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n\n   if (j->succ_high == 0) {\n      // first scan for DC coefficient, must be first\n      memset(data,0,64*sizeof(data[0])); // 0 all the ac values now\n      t = stbi__jpeg_huff_decode(j, hdc);\n      if (t < 0 || t > 15) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n      diff = t ? stbi__extend_receive(j, t) : 0;\n\n      if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err(\"bad delta\", \"Corrupt JPEG\");\n      dc = j->img_comp[b].dc_pred + diff;\n      j->img_comp[b].dc_pred = dc;\n      if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n      data[0] = (short) (dc * (1 << j->succ_low));\n   } else {\n      // refinement scan for DC coefficient\n      if (stbi__jpeg_get_bit(j))\n         data[0] += (short) (1 << j->succ_low);\n   }\n   return 1;\n}\n\n// @OPTIMIZE: store non-zigzagged during the decode passes,\n// and only de-zigzag when dequantizing\nstatic int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)\n{\n   int k;\n   if (j->spec_start == 0) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n\n   if (j->succ_high == 0) {\n      int shift = j->succ_low;\n\n      if (j->eob_run) {\n         --j->eob_run;\n         return 1;\n      }\n\n      k = j->spec_start;\n      do {\n         unsigned int zig;\n         int c,r,s;\n         if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n         r = fac[c];\n         if (r) { // fast-AC path\n            k += (r >> 4) & 15; // run\n            s = r & 15; // combined length\n            if (s > j->code_bits) return stbi__err(\"bad huffman code\", \"Combined length longer than code bits available\");\n            j->code_buffer <<= s;\n            j->code_bits -= s;\n            zig = stbi__jpeg_dezigzag[k++];\n            data[zig] = (short) ((r >> 8) * (1 << shift));\n         } else {\n            int rs = stbi__jpeg_huff_decode(j, hac);\n            if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n            s = rs & 15;\n            r = rs >> 4;\n            if (s == 0) {\n               if (r < 15) {\n                  j->eob_run = (1 << r);\n                  if (r)\n                     j->eob_run += stbi__jpeg_get_bits(j, r);\n                  --j->eob_run;\n                  break;\n               }\n               k += 16;\n            } else {\n               k += r;\n               zig = stbi__jpeg_dezigzag[k++];\n               data[zig] = (short) (stbi__extend_receive(j,s) * (1 << shift));\n            }\n         }\n      } while (k <= j->spec_end);\n   } else {\n      // refinement scan for these AC coefficients\n\n      short bit = (short) (1 << j->succ_low);\n\n      if (j->eob_run) {\n         --j->eob_run;\n         for (k = j->spec_start; k <= j->spec_end; ++k) {\n            short *p = &data[stbi__jpeg_dezigzag[k]];\n            if (*p != 0)\n               if (stbi__jpeg_get_bit(j))\n                  if ((*p & bit)==0) {\n                     if (*p > 0)\n                        *p += bit;\n                     else\n                        *p -= bit;\n                  }\n         }\n      } else {\n         k = j->spec_start;\n         do {\n            int r,s;\n            int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh\n            if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n            s = rs & 15;\n            r = rs >> 4;\n            if (s == 0) {\n               if (r < 15) {\n                  j->eob_run = (1 << r) - 1;\n                  if (r)\n                     j->eob_run += stbi__jpeg_get_bits(j, r);\n                  r = 64; // force end of block\n               } else {\n                  // r=15 s=0 should write 16 0s, so we just do\n                  // a run of 15 0s and then write s (which is 0),\n                  // so we don't have to do anything special here\n               }\n            } else {\n               if (s != 1) return stbi__err(\"bad huffman code\", \"Corrupt JPEG\");\n               // sign bit\n               if (stbi__jpeg_get_bit(j))\n                  s = bit;\n               else\n                  s = -bit;\n            }\n\n            // advance by r\n            while (k <= j->spec_end) {\n               short *p = &data[stbi__jpeg_dezigzag[k++]];\n               if (*p != 0) {\n                  if (stbi__jpeg_get_bit(j))\n                     if ((*p & bit)==0) {\n                        if (*p > 0)\n                           *p += bit;\n                        else\n                           *p -= bit;\n                     }\n               } else {\n                  if (r == 0) {\n                     *p = (short) s;\n                     break;\n                  }\n                  --r;\n               }\n            }\n         } while (k <= j->spec_end);\n      }\n   }\n   return 1;\n}\n\n// take a -128..127 value and stbi__clamp it and convert to 0..255\nstbi_inline static stbi_uc stbi__clamp(int x)\n{\n   // trick to use a single test to catch both cases\n   if ((unsigned int) x > 255) {\n      if (x < 0) return 0;\n      if (x > 255) return 255;\n   }\n   return (stbi_uc) x;\n}\n\n#define stbi__f2f(x)  ((int) (((x) * 4096 + 0.5)))\n#define stbi__fsh(x)  ((x) * 4096)\n\n// derived from jidctint -- DCT_ISLOW\n#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \\\n   int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \\\n   p2 = s2;                                    \\\n   p3 = s6;                                    \\\n   p1 = (p2+p3) * stbi__f2f(0.5411961f);       \\\n   t2 = p1 + p3*stbi__f2f(-1.847759065f);      \\\n   t3 = p1 + p2*stbi__f2f( 0.765366865f);      \\\n   p2 = s0;                                    \\\n   p3 = s4;                                    \\\n   t0 = stbi__fsh(p2+p3);                      \\\n   t1 = stbi__fsh(p2-p3);                      \\\n   x0 = t0+t3;                                 \\\n   x3 = t0-t3;                                 \\\n   x1 = t1+t2;                                 \\\n   x2 = t1-t2;                                 \\\n   t0 = s7;                                    \\\n   t1 = s5;                                    \\\n   t2 = s3;                                    \\\n   t3 = s1;                                    \\\n   p3 = t0+t2;                                 \\\n   p4 = t1+t3;                                 \\\n   p1 = t0+t3;                                 \\\n   p2 = t1+t2;                                 \\\n   p5 = (p3+p4)*stbi__f2f( 1.175875602f);      \\\n   t0 = t0*stbi__f2f( 0.298631336f);           \\\n   t1 = t1*stbi__f2f( 2.053119869f);           \\\n   t2 = t2*stbi__f2f( 3.072711026f);           \\\n   t3 = t3*stbi__f2f( 1.501321110f);           \\\n   p1 = p5 + p1*stbi__f2f(-0.899976223f);      \\\n   p2 = p5 + p2*stbi__f2f(-2.562915447f);      \\\n   p3 = p3*stbi__f2f(-1.961570560f);           \\\n   p4 = p4*stbi__f2f(-0.390180644f);           \\\n   t3 += p1+p4;                                \\\n   t2 += p2+p3;                                \\\n   t1 += p2+p4;                                \\\n   t0 += p1+p3;\n\nstatic void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])\n{\n   int i,val[64],*v=val;\n   stbi_uc *o;\n   short *d = data;\n\n   // columns\n   for (i=0; i < 8; ++i,++d, ++v) {\n      // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing\n      if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0\n           && d[40]==0 && d[48]==0 && d[56]==0) {\n         //    no shortcut                 0     seconds\n         //    (1|2|3|4|5|6|7)==0          0     seconds\n         //    all separate               -0.047 seconds\n         //    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds\n         int dcterm = d[0]*4;\n         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;\n      } else {\n         STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])\n         // constants scaled things up by 1<<12; let's bring them back\n         // down, but keep 2 extra bits of precision\n         x0 += 512; x1 += 512; x2 += 512; x3 += 512;\n         v[ 0] = (x0+t3) >> 10;\n         v[56] = (x0-t3) >> 10;\n         v[ 8] = (x1+t2) >> 10;\n         v[48] = (x1-t2) >> 10;\n         v[16] = (x2+t1) >> 10;\n         v[40] = (x2-t1) >> 10;\n         v[24] = (x3+t0) >> 10;\n         v[32] = (x3-t0) >> 10;\n      }\n   }\n\n   for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {\n      // no fast case since the first 1D IDCT spread components out\n      STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])\n      // constants scaled things up by 1<<12, plus we had 1<<2 from first\n      // loop, plus horizontal and vertical each scale by sqrt(8) so together\n      // we've got an extra 1<<3, so 1<<17 total we need to remove.\n      // so we want to round that, which means adding 0.5 * 1<<17,\n      // aka 65536. Also, we'll end up with -128 to 127 that we want\n      // to encode as 0..255 by adding 128, so we'll add that before the shift\n      x0 += 65536 + (128<<17);\n      x1 += 65536 + (128<<17);\n      x2 += 65536 + (128<<17);\n      x3 += 65536 + (128<<17);\n      // tried computing the shifts into temps, or'ing the temps to see\n      // if any were out of range, but that was slower\n      o[0] = stbi__clamp((x0+t3) >> 17);\n      o[7] = stbi__clamp((x0-t3) >> 17);\n      o[1] = stbi__clamp((x1+t2) >> 17);\n      o[6] = stbi__clamp((x1-t2) >> 17);\n      o[2] = stbi__clamp((x2+t1) >> 17);\n      o[5] = stbi__clamp((x2-t1) >> 17);\n      o[3] = stbi__clamp((x3+t0) >> 17);\n      o[4] = stbi__clamp((x3-t0) >> 17);\n   }\n}\n\n#ifdef STBI_SSE2\n// sse2 integer IDCT. not the fastest possible implementation but it\n// produces bit-identical results to the generic C version so it's\n// fully \"transparent\".\nstatic void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])\n{\n   // This is constructed to match our regular (generic) integer IDCT exactly.\n   __m128i row0, row1, row2, row3, row4, row5, row6, row7;\n   __m128i tmp;\n\n   // dot product constant: even elems=x, odd elems=y\n   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))\n\n   // out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)\n   // out(1) = c1[even]*x + c1[odd]*y\n   #define dct_rot(out0,out1, x,y,c0,c1) \\\n      __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \\\n      __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \\\n      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \\\n      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \\\n      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \\\n      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)\n\n   // out = in << 12  (in 16-bit, out 32-bit)\n   #define dct_widen(out, in) \\\n      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \\\n      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)\n\n   // wide add\n   #define dct_wadd(out, a, b) \\\n      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)\n\n   // wide sub\n   #define dct_wsub(out, a, b) \\\n      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)\n\n   // butterfly a/b, add bias, then shift by \"s\" and pack\n   #define dct_bfly32o(out0, out1, a,b,bias,s) \\\n      { \\\n         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \\\n         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \\\n         dct_wadd(sum, abiased, b); \\\n         dct_wsub(dif, abiased, b); \\\n         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \\\n         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \\\n      }\n\n   // 8-bit interleave step (for transposes)\n   #define dct_interleave8(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi8(a, b); \\\n      b = _mm_unpackhi_epi8(tmp, b)\n\n   // 16-bit interleave step (for transposes)\n   #define dct_interleave16(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi16(a, b); \\\n      b = _mm_unpackhi_epi16(tmp, b)\n\n   #define dct_pass(bias,shift) \\\n      { \\\n         /* even part */ \\\n         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \\\n         __m128i sum04 = _mm_add_epi16(row0, row4); \\\n         __m128i dif04 = _mm_sub_epi16(row0, row4); \\\n         dct_widen(t0e, sum04); \\\n         dct_widen(t1e, dif04); \\\n         dct_wadd(x0, t0e, t3e); \\\n         dct_wsub(x3, t0e, t3e); \\\n         dct_wadd(x1, t1e, t2e); \\\n         dct_wsub(x2, t1e, t2e); \\\n         /* odd part */ \\\n         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \\\n         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \\\n         __m128i sum17 = _mm_add_epi16(row1, row7); \\\n         __m128i sum35 = _mm_add_epi16(row3, row5); \\\n         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \\\n         dct_wadd(x4, y0o, y4o); \\\n         dct_wadd(x5, y1o, y5o); \\\n         dct_wadd(x6, y2o, y5o); \\\n         dct_wadd(x7, y3o, y4o); \\\n         dct_bfly32o(row0,row7, x0,x7,bias,shift); \\\n         dct_bfly32o(row1,row6, x1,x6,bias,shift); \\\n         dct_bfly32o(row2,row5, x2,x5,bias,shift); \\\n         dct_bfly32o(row3,row4, x3,x4,bias,shift); \\\n      }\n\n   __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));\n   __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));\n   __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));\n   __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));\n   __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));\n   __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));\n   __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));\n   __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));\n\n   // rounding biases in column/row passes, see stbi__idct_block for explanation.\n   __m128i bias_0 = _mm_set1_epi32(512);\n   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));\n\n   // load\n   row0 = _mm_load_si128((const __m128i *) (data + 0*8));\n   row1 = _mm_load_si128((const __m128i *) (data + 1*8));\n   row2 = _mm_load_si128((const __m128i *) (data + 2*8));\n   row3 = _mm_load_si128((const __m128i *) (data + 3*8));\n   row4 = _mm_load_si128((const __m128i *) (data + 4*8));\n   row5 = _mm_load_si128((const __m128i *) (data + 5*8));\n   row6 = _mm_load_si128((const __m128i *) (data + 6*8));\n   row7 = _mm_load_si128((const __m128i *) (data + 7*8));\n\n   // column pass\n   dct_pass(bias_0, 10);\n\n   {\n      // 16bit 8x8 transpose pass 1\n      dct_interleave16(row0, row4);\n      dct_interleave16(row1, row5);\n      dct_interleave16(row2, row6);\n      dct_interleave16(row3, row7);\n\n      // transpose pass 2\n      dct_interleave16(row0, row2);\n      dct_interleave16(row1, row3);\n      dct_interleave16(row4, row6);\n      dct_interleave16(row5, row7);\n\n      // transpose pass 3\n      dct_interleave16(row0, row1);\n      dct_interleave16(row2, row3);\n      dct_interleave16(row4, row5);\n      dct_interleave16(row6, row7);\n   }\n\n   // row pass\n   dct_pass(bias_1, 17);\n\n   {\n      // pack\n      __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7\n      __m128i p1 = _mm_packus_epi16(row2, row3);\n      __m128i p2 = _mm_packus_epi16(row4, row5);\n      __m128i p3 = _mm_packus_epi16(row6, row7);\n\n      // 8bit 8x8 transpose pass 1\n      dct_interleave8(p0, p2); // a0e0a1e1...\n      dct_interleave8(p1, p3); // c0g0c1g1...\n\n      // transpose pass 2\n      dct_interleave8(p0, p1); // a0c0e0g0...\n      dct_interleave8(p2, p3); // b0d0f0h0...\n\n      // transpose pass 3\n      dct_interleave8(p0, p2); // a0b0c0d0...\n      dct_interleave8(p1, p3); // a4b4c4d4...\n\n      // store\n      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));\n   }\n\n#undef dct_const\n#undef dct_rot\n#undef dct_widen\n#undef dct_wadd\n#undef dct_wsub\n#undef dct_bfly32o\n#undef dct_interleave8\n#undef dct_interleave16\n#undef dct_pass\n}\n\n#endif // STBI_SSE2\n\n#ifdef STBI_NEON\n\n// NEON integer IDCT. should produce bit-identical\n// results to the generic C version.\nstatic void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])\n{\n   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;\n\n   int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));\n   int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));\n   int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));\n   int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));\n   int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));\n   int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));\n   int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));\n   int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));\n   int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));\n   int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));\n   int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));\n   int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));\n\n#define dct_long_mul(out, inq, coeff) \\\n   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \\\n   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)\n\n#define dct_long_mac(out, acc, inq, coeff) \\\n   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \\\n   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)\n\n#define dct_widen(out, inq) \\\n   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \\\n   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)\n\n// wide add\n#define dct_wadd(out, a, b) \\\n   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \\\n   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)\n\n// wide sub\n#define dct_wsub(out, a, b) \\\n   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \\\n   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)\n\n// butterfly a/b, then shift using \"shiftop\" by \"s\" and pack\n#define dct_bfly32o(out0,out1, a,b,shiftop,s) \\\n   { \\\n      dct_wadd(sum, a, b); \\\n      dct_wsub(dif, a, b); \\\n      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \\\n      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \\\n   }\n\n#define dct_pass(shiftop, shift) \\\n   { \\\n      /* even part */ \\\n      int16x8_t sum26 = vaddq_s16(row2, row6); \\\n      dct_long_mul(p1e, sum26, rot0_0); \\\n      dct_long_mac(t2e, p1e, row6, rot0_1); \\\n      dct_long_mac(t3e, p1e, row2, rot0_2); \\\n      int16x8_t sum04 = vaddq_s16(row0, row4); \\\n      int16x8_t dif04 = vsubq_s16(row0, row4); \\\n      dct_widen(t0e, sum04); \\\n      dct_widen(t1e, dif04); \\\n      dct_wadd(x0, t0e, t3e); \\\n      dct_wsub(x3, t0e, t3e); \\\n      dct_wadd(x1, t1e, t2e); \\\n      dct_wsub(x2, t1e, t2e); \\\n      /* odd part */ \\\n      int16x8_t sum15 = vaddq_s16(row1, row5); \\\n      int16x8_t sum17 = vaddq_s16(row1, row7); \\\n      int16x8_t sum35 = vaddq_s16(row3, row5); \\\n      int16x8_t sum37 = vaddq_s16(row3, row7); \\\n      int16x8_t sumodd = vaddq_s16(sum17, sum35); \\\n      dct_long_mul(p5o, sumodd, rot1_0); \\\n      dct_long_mac(p1o, p5o, sum17, rot1_1); \\\n      dct_long_mac(p2o, p5o, sum35, rot1_2); \\\n      dct_long_mul(p3o, sum37, rot2_0); \\\n      dct_long_mul(p4o, sum15, rot2_1); \\\n      dct_wadd(sump13o, p1o, p3o); \\\n      dct_wadd(sump24o, p2o, p4o); \\\n      dct_wadd(sump23o, p2o, p3o); \\\n      dct_wadd(sump14o, p1o, p4o); \\\n      dct_long_mac(x4, sump13o, row7, rot3_0); \\\n      dct_long_mac(x5, sump24o, row5, rot3_1); \\\n      dct_long_mac(x6, sump23o, row3, rot3_2); \\\n      dct_long_mac(x7, sump14o, row1, rot3_3); \\\n      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \\\n      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \\\n      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \\\n      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \\\n   }\n\n   // load\n   row0 = vld1q_s16(data + 0*8);\n   row1 = vld1q_s16(data + 1*8);\n   row2 = vld1q_s16(data + 2*8);\n   row3 = vld1q_s16(data + 3*8);\n   row4 = vld1q_s16(data + 4*8);\n   row5 = vld1q_s16(data + 5*8);\n   row6 = vld1q_s16(data + 6*8);\n   row7 = vld1q_s16(data + 7*8);\n\n   // add DC bias\n   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));\n\n   // column pass\n   dct_pass(vrshrn_n_s32, 10);\n\n   // 16bit 8x8 transpose\n   {\n// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.\n// whether compilers actually get this is another story, sadly.\n#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }\n#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }\n#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }\n\n      // pass 1\n      dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6\n      dct_trn16(row2, row3);\n      dct_trn16(row4, row5);\n      dct_trn16(row6, row7);\n\n      // pass 2\n      dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4\n      dct_trn32(row1, row3);\n      dct_trn32(row4, row6);\n      dct_trn32(row5, row7);\n\n      // pass 3\n      dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0\n      dct_trn64(row1, row5);\n      dct_trn64(row2, row6);\n      dct_trn64(row3, row7);\n\n#undef dct_trn16\n#undef dct_trn32\n#undef dct_trn64\n   }\n\n   // row pass\n   // vrshrn_n_s32 only supports shifts up to 16, we need\n   // 17. so do a non-rounding shift of 16 first then follow\n   // up with a rounding shift by 1.\n   dct_pass(vshrn_n_s32, 16);\n\n   {\n      // pack and round\n      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);\n      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);\n      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);\n      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);\n      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);\n      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);\n      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);\n      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);\n\n      // again, these can translate into one instruction, but often don't.\n#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }\n#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }\n#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }\n\n      // sadly can't use interleaved stores here since we only write\n      // 8 bytes to each scan line!\n\n      // 8x8 8-bit transpose pass 1\n      dct_trn8_8(p0, p1);\n      dct_trn8_8(p2, p3);\n      dct_trn8_8(p4, p5);\n      dct_trn8_8(p6, p7);\n\n      // pass 2\n      dct_trn8_16(p0, p2);\n      dct_trn8_16(p1, p3);\n      dct_trn8_16(p4, p6);\n      dct_trn8_16(p5, p7);\n\n      // pass 3\n      dct_trn8_32(p0, p4);\n      dct_trn8_32(p1, p5);\n      dct_trn8_32(p2, p6);\n      dct_trn8_32(p3, p7);\n\n      // store\n      vst1_u8(out, p0); out += out_stride;\n      vst1_u8(out, p1); out += out_stride;\n      vst1_u8(out, p2); out += out_stride;\n      vst1_u8(out, p3); out += out_stride;\n      vst1_u8(out, p4); out += out_stride;\n      vst1_u8(out, p5); out += out_stride;\n      vst1_u8(out, p6); out += out_stride;\n      vst1_u8(out, p7);\n\n#undef dct_trn8_8\n#undef dct_trn8_16\n#undef dct_trn8_32\n   }\n\n#undef dct_long_mul\n#undef dct_long_mac\n#undef dct_widen\n#undef dct_wadd\n#undef dct_wsub\n#undef dct_bfly32o\n#undef dct_pass\n}\n\n#endif // STBI_NEON\n\n#define STBI__MARKER_none  0xff\n// if there's a pending marker from the entropy stream, return that\n// otherwise, fetch from the stream and get a marker. if there's no\n// marker, return 0xff, which is never a valid marker value\nstatic stbi_uc stbi__get_marker(stbi__jpeg *j)\n{\n   stbi_uc x;\n   if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }\n   x = stbi__get8(j->s);\n   if (x != 0xff) return STBI__MARKER_none;\n   while (x == 0xff)\n      x = stbi__get8(j->s); // consume repeated 0xff fill bytes\n   return x;\n}\n\n// in each scan, we'll have scan_n components, and the order\n// of the components is specified by order[]\n#define STBI__RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)\n\n// after a restart interval, stbi__jpeg_reset the entropy decoder and\n// the dc prediction\nstatic void stbi__jpeg_reset(stbi__jpeg *j)\n{\n   j->code_bits = 0;\n   j->code_buffer = 0;\n   j->nomore = 0;\n   j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = j->img_comp[3].dc_pred = 0;\n   j->marker = STBI__MARKER_none;\n   j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;\n   j->eob_run = 0;\n   // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,\n   // since we don't even allow 1<<30 pixels\n}\n\nstatic int stbi__parse_entropy_coded_data(stbi__jpeg *z)\n{\n   stbi__jpeg_reset(z);\n   if (!z->progressive) {\n      if (z->scan_n == 1) {\n         int i,j;\n         STBI_SIMD_ALIGN(short, data[64]);\n         int n = z->order[0];\n         // non-interleaved data, we just need to process one block at a time,\n         // in trivial scanline order\n         // number of blocks to do just depends on how many actual \"pixels\" this\n         // component has, independent of interleaved MCU blocking and such\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               int ha = z->img_comp[n].ha;\n               if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;\n               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);\n               // every data block is an MCU, so countdown the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  // if it's NOT a restart, then just bail, so we get corrupt data\n                  // rather than no data\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      } else { // interleaved\n         int i,j,k,x,y;\n         STBI_SIMD_ALIGN(short, data[64]);\n         for (j=0; j < z->img_mcu_y; ++j) {\n            for (i=0; i < z->img_mcu_x; ++i) {\n               // scan an interleaved mcu... process scan_n components in order\n               for (k=0; k < z->scan_n; ++k) {\n                  int n = z->order[k];\n                  // scan out an mcu's worth of this component; that's just determined\n                  // by the basic H and V specified for the component\n                  for (y=0; y < z->img_comp[n].v; ++y) {\n                     for (x=0; x < z->img_comp[n].h; ++x) {\n                        int x2 = (i*z->img_comp[n].h + x)*8;\n                        int y2 = (j*z->img_comp[n].v + y)*8;\n                        int ha = z->img_comp[n].ha;\n                        if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;\n                        z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);\n                     }\n                  }\n               }\n               // after all interleaved components, that's an interleaved MCU,\n               // so now count down the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      }\n   } else {\n      if (z->scan_n == 1) {\n         int i,j;\n         int n = z->order[0];\n         // non-interleaved data, we just need to process one block at a time,\n         // in trivial scanline order\n         // number of blocks to do just depends on how many actual \"pixels\" this\n         // component has, independent of interleaved MCU blocking and such\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);\n               if (z->spec_start == 0) {\n                  if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))\n                     return 0;\n               } else {\n                  int ha = z->img_comp[n].ha;\n                  if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))\n                     return 0;\n               }\n               // every data block is an MCU, so countdown the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      } else { // interleaved\n         int i,j,k,x,y;\n         for (j=0; j < z->img_mcu_y; ++j) {\n            for (i=0; i < z->img_mcu_x; ++i) {\n               // scan an interleaved mcu... process scan_n components in order\n               for (k=0; k < z->scan_n; ++k) {\n                  int n = z->order[k];\n                  // scan out an mcu's worth of this component; that's just determined\n                  // by the basic H and V specified for the component\n                  for (y=0; y < z->img_comp[n].v; ++y) {\n                     for (x=0; x < z->img_comp[n].h; ++x) {\n                        int x2 = (i*z->img_comp[n].h + x);\n                        int y2 = (j*z->img_comp[n].v + y);\n                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);\n                        if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))\n                           return 0;\n                     }\n                  }\n               }\n               // after all interleaved components, that's an interleaved MCU,\n               // so now count down the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      }\n   }\n}\n\nstatic void stbi__jpeg_dequantize(short *data, stbi__uint16 *dequant)\n{\n   int i;\n   for (i=0; i < 64; ++i)\n      data[i] *= dequant[i];\n}\n\nstatic void stbi__jpeg_finish(stbi__jpeg *z)\n{\n   if (z->progressive) {\n      // dequantize and idct the data\n      int i,j,n;\n      for (n=0; n < z->s->img_n; ++n) {\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);\n               stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);\n               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);\n            }\n         }\n      }\n   }\n}\n\nstatic int stbi__process_marker(stbi__jpeg *z, int m)\n{\n   int L;\n   switch (m) {\n      case STBI__MARKER_none: // no marker found\n         return stbi__err(\"expected marker\",\"Corrupt JPEG\");\n\n      case 0xDD: // DRI - specify restart interval\n         if (stbi__get16be(z->s) != 4) return stbi__err(\"bad DRI len\",\"Corrupt JPEG\");\n         z->restart_interval = stbi__get16be(z->s);\n         return 1;\n\n      case 0xDB: // DQT - define quantization table\n         L = stbi__get16be(z->s)-2;\n         while (L > 0) {\n            int q = stbi__get8(z->s);\n            int p = q >> 4, sixteen = (p != 0);\n            int t = q & 15,i;\n            if (p != 0 && p != 1) return stbi__err(\"bad DQT type\",\"Corrupt JPEG\");\n            if (t > 3) return stbi__err(\"bad DQT table\",\"Corrupt JPEG\");\n\n            for (i=0; i < 64; ++i)\n               z->dequant[t][stbi__jpeg_dezigzag[i]] = (stbi__uint16)(sixteen ? stbi__get16be(z->s) : stbi__get8(z->s));\n            L -= (sixteen ? 129 : 65);\n         }\n         return L==0;\n\n      case 0xC4: // DHT - define huffman table\n         L = stbi__get16be(z->s)-2;\n         while (L > 0) {\n            stbi_uc *v;\n            int sizes[16],i,n=0;\n            int q = stbi__get8(z->s);\n            int tc = q >> 4;\n            int th = q & 15;\n            if (tc > 1 || th > 3) return stbi__err(\"bad DHT header\",\"Corrupt JPEG\");\n            for (i=0; i < 16; ++i) {\n               sizes[i] = stbi__get8(z->s);\n               n += sizes[i];\n            }\n            if(n > 256) return stbi__err(\"bad DHT header\",\"Corrupt JPEG\"); // Loop over i < n would write past end of values!\n            L -= 17;\n            if (tc == 0) {\n               if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;\n               v = z->huff_dc[th].values;\n            } else {\n               if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;\n               v = z->huff_ac[th].values;\n            }\n            for (i=0; i < n; ++i)\n               v[i] = stbi__get8(z->s);\n            if (tc != 0)\n               stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);\n            L -= n;\n         }\n         return L==0;\n   }\n\n   // check for comment block or APP blocks\n   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {\n      L = stbi__get16be(z->s);\n      if (L < 2) {\n         if (m == 0xFE)\n            return stbi__err(\"bad COM len\",\"Corrupt JPEG\");\n         else\n            return stbi__err(\"bad APP len\",\"Corrupt JPEG\");\n      }\n      L -= 2;\n\n      if (m == 0xE0 && L >= 5) { // JFIF APP0 segment\n         static const unsigned char tag[5] = {'J','F','I','F','\\0'};\n         int ok = 1;\n         int i;\n         for (i=0; i < 5; ++i)\n            if (stbi__get8(z->s) != tag[i])\n               ok = 0;\n         L -= 5;\n         if (ok)\n            z->jfif = 1;\n      } else if (m == 0xEE && L >= 12) { // Adobe APP14 segment\n         static const unsigned char tag[6] = {'A','d','o','b','e','\\0'};\n         int ok = 1;\n         int i;\n         for (i=0; i < 6; ++i)\n            if (stbi__get8(z->s) != tag[i])\n               ok = 0;\n         L -= 6;\n         if (ok) {\n            stbi__get8(z->s); // version\n            stbi__get16be(z->s); // flags0\n            stbi__get16be(z->s); // flags1\n            z->app14_color_transform = stbi__get8(z->s); // color transform\n            L -= 6;\n         }\n      }\n\n      stbi__skip(z->s, L);\n      return 1;\n   }\n\n   return stbi__err(\"unknown marker\",\"Corrupt JPEG\");\n}\n\n// after we see SOS\nstatic int stbi__process_scan_header(stbi__jpeg *z)\n{\n   int i;\n   int Ls = stbi__get16be(z->s);\n   z->scan_n = stbi__get8(z->s);\n   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err(\"bad SOS component count\",\"Corrupt JPEG\");\n   if (Ls != 6+2*z->scan_n) return stbi__err(\"bad SOS len\",\"Corrupt JPEG\");\n   for (i=0; i < z->scan_n; ++i) {\n      int id = stbi__get8(z->s), which;\n      int q = stbi__get8(z->s);\n      for (which = 0; which < z->s->img_n; ++which)\n         if (z->img_comp[which].id == id)\n            break;\n      if (which == z->s->img_n) return 0; // no match\n      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3) return stbi__err(\"bad DC huff\",\"Corrupt JPEG\");\n      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3) return stbi__err(\"bad AC huff\",\"Corrupt JPEG\");\n      z->order[i] = which;\n   }\n\n   {\n      int aa;\n      z->spec_start = stbi__get8(z->s);\n      z->spec_end   = stbi__get8(z->s); // should be 63, but might be 0\n      aa = stbi__get8(z->s);\n      z->succ_high = (aa >> 4);\n      z->succ_low  = (aa & 15);\n      if (z->progressive) {\n         if (z->spec_start > 63 || z->spec_end > 63  || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)\n            return stbi__err(\"bad SOS\", \"Corrupt JPEG\");\n      } else {\n         if (z->spec_start != 0) return stbi__err(\"bad SOS\",\"Corrupt JPEG\");\n         if (z->succ_high != 0 || z->succ_low != 0) return stbi__err(\"bad SOS\",\"Corrupt JPEG\");\n         z->spec_end = 63;\n      }\n   }\n\n   return 1;\n}\n\nstatic int stbi__free_jpeg_components(stbi__jpeg *z, int ncomp, int why)\n{\n   int i;\n   for (i=0; i < ncomp; ++i) {\n      if (z->img_comp[i].raw_data) {\n         STBI_FREE(z->img_comp[i].raw_data);\n         z->img_comp[i].raw_data = NULL;\n         z->img_comp[i].data = NULL;\n      }\n      if (z->img_comp[i].raw_coeff) {\n         STBI_FREE(z->img_comp[i].raw_coeff);\n         z->img_comp[i].raw_coeff = 0;\n         z->img_comp[i].coeff = 0;\n      }\n      if (z->img_comp[i].linebuf) {\n         STBI_FREE(z->img_comp[i].linebuf);\n         z->img_comp[i].linebuf = NULL;\n      }\n   }\n   return why;\n}\n\nstatic int stbi__process_frame_header(stbi__jpeg *z, int scan)\n{\n   stbi__context *s = z->s;\n   int Lf,p,i,q, h_max=1,v_max=1,c;\n   Lf = stbi__get16be(s);         if (Lf < 11) return stbi__err(\"bad SOF len\",\"Corrupt JPEG\"); // JPEG\n   p  = stbi__get8(s);            if (p != 8) return stbi__err(\"only 8-bit\",\"JPEG format not supported: 8-bit only\"); // JPEG baseline\n   s->img_y = stbi__get16be(s);   if (s->img_y == 0) return stbi__err(\"no header height\", \"JPEG format not supported: delayed height\"); // Legal, but we don't handle it--but neither does IJG\n   s->img_x = stbi__get16be(s);   if (s->img_x == 0) return stbi__err(\"0 width\",\"Corrupt JPEG\"); // JPEG requires\n   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n   c = stbi__get8(s);\n   if (c != 3 && c != 1 && c != 4) return stbi__err(\"bad component count\",\"Corrupt JPEG\");\n   s->img_n = c;\n   for (i=0; i < c; ++i) {\n      z->img_comp[i].data = NULL;\n      z->img_comp[i].linebuf = NULL;\n   }\n\n   if (Lf != 8+3*s->img_n) return stbi__err(\"bad SOF len\",\"Corrupt JPEG\");\n\n   z->rgb = 0;\n   for (i=0; i < s->img_n; ++i) {\n      static const unsigned char rgb[3] = { 'R', 'G', 'B' };\n      z->img_comp[i].id = stbi__get8(s);\n      if (s->img_n == 3 && z->img_comp[i].id == rgb[i])\n         ++z->rgb;\n      q = stbi__get8(s);\n      z->img_comp[i].h = (q >> 4);  if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err(\"bad H\",\"Corrupt JPEG\");\n      z->img_comp[i].v = q & 15;    if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err(\"bad V\",\"Corrupt JPEG\");\n      z->img_comp[i].tq = stbi__get8(s);  if (z->img_comp[i].tq > 3) return stbi__err(\"bad TQ\",\"Corrupt JPEG\");\n   }\n\n   if (scan != STBI__SCAN_load) return 1;\n\n   if (!stbi__mad3sizes_valid(s->img_x, s->img_y, s->img_n, 0)) return stbi__err(\"too large\", \"Image too large to decode\");\n\n   for (i=0; i < s->img_n; ++i) {\n      if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;\n      if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;\n   }\n\n   // check that plane subsampling factors are integer ratios; our resamplers can't deal with fractional ratios\n   // and I've never seen a non-corrupted JPEG file actually use them\n   for (i=0; i < s->img_n; ++i) {\n      if (h_max % z->img_comp[i].h != 0) return stbi__err(\"bad H\",\"Corrupt JPEG\");\n      if (v_max % z->img_comp[i].v != 0) return stbi__err(\"bad V\",\"Corrupt JPEG\");\n   }\n\n   // compute interleaved mcu info\n   z->img_h_max = h_max;\n   z->img_v_max = v_max;\n   z->img_mcu_w = h_max * 8;\n   z->img_mcu_h = v_max * 8;\n   // these sizes can't be more than 17 bits\n   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;\n   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;\n\n   for (i=0; i < s->img_n; ++i) {\n      // number of effective pixels (e.g. for non-interleaved MCU)\n      z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;\n      z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;\n      // to simplify generation, we'll allocate enough memory to decode\n      // the bogus oversized data from using interleaved MCUs and their\n      // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't\n      // discard the extra data until colorspace conversion\n      //\n      // img_mcu_x, img_mcu_y: <=17 bits; comp[i].h and .v are <=4 (checked earlier)\n      // so these muls can't overflow with 32-bit ints (which we require)\n      z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;\n      z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;\n      z->img_comp[i].coeff = 0;\n      z->img_comp[i].raw_coeff = 0;\n      z->img_comp[i].linebuf = NULL;\n      z->img_comp[i].raw_data = stbi__malloc_mad2(z->img_comp[i].w2, z->img_comp[i].h2, 15);\n      if (z->img_comp[i].raw_data == NULL)\n         return stbi__free_jpeg_components(z, i+1, stbi__err(\"outofmem\", \"Out of memory\"));\n      // align blocks for idct using mmx/sse\n      z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);\n      if (z->progressive) {\n         // w2, h2 are multiples of 8 (see above)\n         z->img_comp[i].coeff_w = z->img_comp[i].w2 / 8;\n         z->img_comp[i].coeff_h = z->img_comp[i].h2 / 8;\n         z->img_comp[i].raw_coeff = stbi__malloc_mad3(z->img_comp[i].w2, z->img_comp[i].h2, sizeof(short), 15);\n         if (z->img_comp[i].raw_coeff == NULL)\n            return stbi__free_jpeg_components(z, i+1, stbi__err(\"outofmem\", \"Out of memory\"));\n         z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);\n      }\n   }\n\n   return 1;\n}\n\n// use comparisons since in some cases we handle more than one case (e.g. SOF)\n#define stbi__DNL(x)         ((x) == 0xdc)\n#define stbi__SOI(x)         ((x) == 0xd8)\n#define stbi__EOI(x)         ((x) == 0xd9)\n#define stbi__SOF(x)         ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)\n#define stbi__SOS(x)         ((x) == 0xda)\n\n#define stbi__SOF_progressive(x)   ((x) == 0xc2)\n\nstatic int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)\n{\n   int m;\n   z->jfif = 0;\n   z->app14_color_transform = -1; // valid values are 0,1,2\n   z->marker = STBI__MARKER_none; // initialize cached marker to empty\n   m = stbi__get_marker(z);\n   if (!stbi__SOI(m)) return stbi__err(\"no SOI\",\"Corrupt JPEG\");\n   if (scan == STBI__SCAN_type) return 1;\n   m = stbi__get_marker(z);\n   while (!stbi__SOF(m)) {\n      if (!stbi__process_marker(z,m)) return 0;\n      m = stbi__get_marker(z);\n      while (m == STBI__MARKER_none) {\n         // some files have extra padding after their blocks, so ok, we'll scan\n         if (stbi__at_eof(z->s)) return stbi__err(\"no SOF\", \"Corrupt JPEG\");\n         m = stbi__get_marker(z);\n      }\n   }\n   z->progressive = stbi__SOF_progressive(m);\n   if (!stbi__process_frame_header(z, scan)) return 0;\n   return 1;\n}\n\nstatic int stbi__skip_jpeg_junk_at_end(stbi__jpeg *j)\n{\n   // some JPEGs have junk at end, skip over it but if we find what looks\n   // like a valid marker, resume there\n   while (!stbi__at_eof(j->s)) {\n      int x = stbi__get8(j->s);\n      while (x == 255) { // might be a marker\n         if (stbi__at_eof(j->s)) return STBI__MARKER_none;\n         x = stbi__get8(j->s);\n         if (x != 0x00 && x != 0xff) {\n            // not a stuffed zero or lead-in to another marker, looks\n            // like an actual marker, return it\n            return x;\n         }\n         // stuffed zero has x=0 now which ends the loop, meaning we go\n         // back to regular scan loop.\n         // repeated 0xff keeps trying to read the next byte of the marker.\n      }\n   }\n   return STBI__MARKER_none;\n}\n\n// decode image to YCbCr format\nstatic int stbi__decode_jpeg_image(stbi__jpeg *j)\n{\n   int m;\n   for (m = 0; m < 4; m++) {\n      j->img_comp[m].raw_data = NULL;\n      j->img_comp[m].raw_coeff = NULL;\n   }\n   j->restart_interval = 0;\n   if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;\n   m = stbi__get_marker(j);\n   while (!stbi__EOI(m)) {\n      if (stbi__SOS(m)) {\n         if (!stbi__process_scan_header(j)) return 0;\n         if (!stbi__parse_entropy_coded_data(j)) return 0;\n         if (j->marker == STBI__MARKER_none ) {\n         j->marker = stbi__skip_jpeg_junk_at_end(j);\n            // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0\n         }\n         m = stbi__get_marker(j);\n         if (STBI__RESTART(m))\n            m = stbi__get_marker(j);\n      } else if (stbi__DNL(m)) {\n         int Ld = stbi__get16be(j->s);\n         stbi__uint32 NL = stbi__get16be(j->s);\n         if (Ld != 4) return stbi__err(\"bad DNL len\", \"Corrupt JPEG\");\n         if (NL != j->s->img_y) return stbi__err(\"bad DNL height\", \"Corrupt JPEG\");\n         m = stbi__get_marker(j);\n      } else {\n         if (!stbi__process_marker(j, m)) return 1;\n         m = stbi__get_marker(j);\n      }\n   }\n   if (j->progressive)\n      stbi__jpeg_finish(j);\n   return 1;\n}\n\n// static jfif-centered resampling (across block boundaries)\n\ntypedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,\n                                    int w, int hs);\n\n#define stbi__div4(x) ((stbi_uc) ((x) >> 2))\n\nstatic stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   STBI_NOTUSED(out);\n   STBI_NOTUSED(in_far);\n   STBI_NOTUSED(w);\n   STBI_NOTUSED(hs);\n   return in_near;\n}\n\nstatic stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate two samples vertically for every one in input\n   int i;\n   STBI_NOTUSED(hs);\n   for (i=0; i < w; ++i)\n      out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);\n   return out;\n}\n\nstatic stbi_uc*  stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate two samples horizontally for every one in input\n   int i;\n   stbi_uc *input = in_near;\n\n   if (w == 1) {\n      // if only one sample, can't do any interpolation\n      out[0] = out[1] = input[0];\n      return out;\n   }\n\n   out[0] = input[0];\n   out[1] = stbi__div4(input[0]*3 + input[1] + 2);\n   for (i=1; i < w-1; ++i) {\n      int n = 3*input[i]+2;\n      out[i*2+0] = stbi__div4(n+input[i-1]);\n      out[i*2+1] = stbi__div4(n+input[i+1]);\n   }\n   out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);\n   out[i*2+1] = input[w-1];\n\n   STBI_NOTUSED(in_far);\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n\n#define stbi__div16(x) ((stbi_uc) ((x) >> 4))\n\nstatic stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate 2x2 samples for every one in input\n   int i,t0,t1;\n   if (w == 1) {\n      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);\n      return out;\n   }\n\n   t1 = 3*in_near[0] + in_far[0];\n   out[0] = stbi__div4(t1+2);\n   for (i=1; i < w; ++i) {\n      t0 = t1;\n      t1 = 3*in_near[i]+in_far[i];\n      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);\n      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);\n   }\n   out[w*2-1] = stbi__div4(t1+2);\n\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n\n#if defined(STBI_SSE2) || defined(STBI_NEON)\nstatic stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate 2x2 samples for every one in input\n   int i=0,t0,t1;\n\n   if (w == 1) {\n      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);\n      return out;\n   }\n\n   t1 = 3*in_near[0] + in_far[0];\n   // process groups of 8 pixels for as long as we can.\n   // note we can't handle the last pixel in a row in this loop\n   // because we need to handle the filter boundary conditions.\n   for (; i < ((w-1) & ~7); i += 8) {\n#if defined(STBI_SSE2)\n      // load and perform the vertical filtering pass\n      // this uses 3*x + y = 4*x + (y - x)\n      __m128i zero  = _mm_setzero_si128();\n      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));\n      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));\n      __m128i farw  = _mm_unpacklo_epi8(farb, zero);\n      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);\n      __m128i diff  = _mm_sub_epi16(farw, nearw);\n      __m128i nears = _mm_slli_epi16(nearw, 2);\n      __m128i curr  = _mm_add_epi16(nears, diff); // current row\n\n      // horizontal filter works the same based on shifted vers of current\n      // row. \"prev\" is current row shifted right by 1 pixel; we need to\n      // insert the previous pixel value (from t1).\n      // \"next\" is current row shifted left by 1 pixel, with first pixel\n      // of next block of 8 pixels added in.\n      __m128i prv0 = _mm_slli_si128(curr, 2);\n      __m128i nxt0 = _mm_srli_si128(curr, 2);\n      __m128i prev = _mm_insert_epi16(prv0, t1, 0);\n      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);\n\n      // horizontal filter, polyphase implementation since it's convenient:\n      // even pixels = 3*cur + prev = cur*4 + (prev - cur)\n      // odd  pixels = 3*cur + next = cur*4 + (next - cur)\n      // note the shared term.\n      __m128i bias  = _mm_set1_epi16(8);\n      __m128i curs = _mm_slli_epi16(curr, 2);\n      __m128i prvd = _mm_sub_epi16(prev, curr);\n      __m128i nxtd = _mm_sub_epi16(next, curr);\n      __m128i curb = _mm_add_epi16(curs, bias);\n      __m128i even = _mm_add_epi16(prvd, curb);\n      __m128i odd  = _mm_add_epi16(nxtd, curb);\n\n      // interleave even and odd pixels, then undo scaling.\n      __m128i int0 = _mm_unpacklo_epi16(even, odd);\n      __m128i int1 = _mm_unpackhi_epi16(even, odd);\n      __m128i de0  = _mm_srli_epi16(int0, 4);\n      __m128i de1  = _mm_srli_epi16(int1, 4);\n\n      // pack and write output\n      __m128i outv = _mm_packus_epi16(de0, de1);\n      _mm_storeu_si128((__m128i *) (out + i*2), outv);\n#elif defined(STBI_NEON)\n      // load and perform the vertical filtering pass\n      // this uses 3*x + y = 4*x + (y - x)\n      uint8x8_t farb  = vld1_u8(in_far + i);\n      uint8x8_t nearb = vld1_u8(in_near + i);\n      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));\n      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));\n      int16x8_t curr  = vaddq_s16(nears, diff); // current row\n\n      // horizontal filter works the same based on shifted vers of current\n      // row. \"prev\" is current row shifted right by 1 pixel; we need to\n      // insert the previous pixel value (from t1).\n      // \"next\" is current row shifted left by 1 pixel, with first pixel\n      // of next block of 8 pixels added in.\n      int16x8_t prv0 = vextq_s16(curr, curr, 7);\n      int16x8_t nxt0 = vextq_s16(curr, curr, 1);\n      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);\n      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);\n\n      // horizontal filter, polyphase implementation since it's convenient:\n      // even pixels = 3*cur + prev = cur*4 + (prev - cur)\n      // odd  pixels = 3*cur + next = cur*4 + (next - cur)\n      // note the shared term.\n      int16x8_t curs = vshlq_n_s16(curr, 2);\n      int16x8_t prvd = vsubq_s16(prev, curr);\n      int16x8_t nxtd = vsubq_s16(next, curr);\n      int16x8_t even = vaddq_s16(curs, prvd);\n      int16x8_t odd  = vaddq_s16(curs, nxtd);\n\n      // undo scaling and round, then store with even/odd phases interleaved\n      uint8x8x2_t o;\n      o.val[0] = vqrshrun_n_s16(even, 4);\n      o.val[1] = vqrshrun_n_s16(odd,  4);\n      vst2_u8(out + i*2, o);\n#endif\n\n      // \"previous\" value for next iter\n      t1 = 3*in_near[i+7] + in_far[i+7];\n   }\n\n   t0 = t1;\n   t1 = 3*in_near[i] + in_far[i];\n   out[i*2] = stbi__div16(3*t1 + t0 + 8);\n\n   for (++i; i < w; ++i) {\n      t0 = t1;\n      t1 = 3*in_near[i]+in_far[i];\n      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);\n      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);\n   }\n   out[w*2-1] = stbi__div4(t1+2);\n\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n#endif\n\nstatic stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // resample with nearest-neighbor\n   int i,j;\n   STBI_NOTUSED(in_far);\n   for (i=0; i < w; ++i)\n      for (j=0; j < hs; ++j)\n         out[i*hs+j] = in_near[i];\n   return out;\n}\n\n// this is a reduced-precision calculation of YCbCr-to-RGB introduced\n// to make sure the code produces the same results in both SIMD and scalar\n#define stbi__float2fixed(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)\nstatic void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)\n{\n   int i;\n   for (i=0; i < count; ++i) {\n      int y_fixed = (y[i] << 20) + (1<<19); // rounding\n      int r,g,b;\n      int cr = pcr[i] - 128;\n      int cb = pcb[i] - 128;\n      r = y_fixed +  cr* stbi__float2fixed(1.40200f);\n      g = y_fixed + (cr*-stbi__float2fixed(0.71414f)) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);\n      b = y_fixed                                     +   cb* stbi__float2fixed(1.77200f);\n      r >>= 20;\n      g >>= 20;\n      b >>= 20;\n      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }\n      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }\n      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }\n      out[0] = (stbi_uc)r;\n      out[1] = (stbi_uc)g;\n      out[2] = (stbi_uc)b;\n      out[3] = 255;\n      out += step;\n   }\n}\n\n#if defined(STBI_SSE2) || defined(STBI_NEON)\nstatic void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)\n{\n   int i = 0;\n\n#ifdef STBI_SSE2\n   // step == 3 is pretty ugly on the final interleave, and i'm not convinced\n   // it's useful in practice (you wouldn't use it for textures, for example).\n   // so just accelerate step == 4 case.\n   if (step == 4) {\n      // this is a fairly straightforward implementation and not super-optimized.\n      __m128i signflip  = _mm_set1_epi8(-0x80);\n      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));\n      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));\n      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));\n      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));\n      __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);\n      __m128i xw = _mm_set1_epi16(255); // alpha channel\n\n      for (; i+7 < count; i += 8) {\n         // load\n         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));\n         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));\n         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));\n         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128\n         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128\n\n         // unpack to short (and left-shift cr, cb by 8)\n         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);\n         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);\n         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);\n\n         // color transform\n         __m128i yws = _mm_srli_epi16(yw, 4);\n         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);\n         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);\n         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);\n         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);\n         __m128i rws = _mm_add_epi16(cr0, yws);\n         __m128i gwt = _mm_add_epi16(cb0, yws);\n         __m128i bws = _mm_add_epi16(yws, cb1);\n         __m128i gws = _mm_add_epi16(gwt, cr1);\n\n         // descale\n         __m128i rw = _mm_srai_epi16(rws, 4);\n         __m128i bw = _mm_srai_epi16(bws, 4);\n         __m128i gw = _mm_srai_epi16(gws, 4);\n\n         // back to byte, set up for transpose\n         __m128i brb = _mm_packus_epi16(rw, bw);\n         __m128i gxb = _mm_packus_epi16(gw, xw);\n\n         // transpose to interleave channels\n         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);\n         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);\n         __m128i o0 = _mm_unpacklo_epi16(t0, t1);\n         __m128i o1 = _mm_unpackhi_epi16(t0, t1);\n\n         // store\n         _mm_storeu_si128((__m128i *) (out + 0), o0);\n         _mm_storeu_si128((__m128i *) (out + 16), o1);\n         out += 32;\n      }\n   }\n#endif\n\n#ifdef STBI_NEON\n   // in this version, step=3 support would be easy to add. but is there demand?\n   if (step == 4) {\n      // this is a fairly straightforward implementation and not super-optimized.\n      uint8x8_t signflip = vdup_n_u8(0x80);\n      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));\n      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));\n      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));\n      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));\n\n      for (; i+7 < count; i += 8) {\n         // load\n         uint8x8_t y_bytes  = vld1_u8(y + i);\n         uint8x8_t cr_bytes = vld1_u8(pcr + i);\n         uint8x8_t cb_bytes = vld1_u8(pcb + i);\n         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));\n         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));\n\n         // expand to s16\n         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));\n         int16x8_t crw = vshll_n_s8(cr_biased, 7);\n         int16x8_t cbw = vshll_n_s8(cb_biased, 7);\n\n         // color transform\n         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);\n         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);\n         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);\n         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);\n         int16x8_t rws = vaddq_s16(yws, cr0);\n         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);\n         int16x8_t bws = vaddq_s16(yws, cb1);\n\n         // undo scaling, round, convert to byte\n         uint8x8x4_t o;\n         o.val[0] = vqrshrun_n_s16(rws, 4);\n         o.val[1] = vqrshrun_n_s16(gws, 4);\n         o.val[2] = vqrshrun_n_s16(bws, 4);\n         o.val[3] = vdup_n_u8(255);\n\n         // store, interleaving r/g/b/a\n         vst4_u8(out, o);\n         out += 8*4;\n      }\n   }\n#endif\n\n   for (; i < count; ++i) {\n      int y_fixed = (y[i] << 20) + (1<<19); // rounding\n      int r,g,b;\n      int cr = pcr[i] - 128;\n      int cb = pcb[i] - 128;\n      r = y_fixed + cr* stbi__float2fixed(1.40200f);\n      g = y_fixed + cr*-stbi__float2fixed(0.71414f) + ((cb*-stbi__float2fixed(0.34414f)) & 0xffff0000);\n      b = y_fixed                                   +   cb* stbi__float2fixed(1.77200f);\n      r >>= 20;\n      g >>= 20;\n      b >>= 20;\n      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }\n      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }\n      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }\n      out[0] = (stbi_uc)r;\n      out[1] = (stbi_uc)g;\n      out[2] = (stbi_uc)b;\n      out[3] = 255;\n      out += step;\n   }\n}\n#endif\n\n// set up the kernels\nstatic void stbi__setup_jpeg(stbi__jpeg *j)\n{\n   j->idct_block_kernel = stbi__idct_block;\n   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;\n   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;\n\n#ifdef STBI_SSE2\n   if (stbi__sse2_available()) {\n      j->idct_block_kernel = stbi__idct_simd;\n      j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;\n      j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;\n   }\n#endif\n\n#ifdef STBI_NEON\n   j->idct_block_kernel = stbi__idct_simd;\n   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;\n   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;\n#endif\n}\n\n// clean up the temporary component buffers\nstatic void stbi__cleanup_jpeg(stbi__jpeg *j)\n{\n   stbi__free_jpeg_components(j, j->s->img_n, 0);\n}\n\ntypedef struct\n{\n   resample_row_func resample;\n   stbi_uc *line0,*line1;\n   int hs,vs;   // expansion factor in each axis\n   int w_lores; // horizontal pixels pre-expansion\n   int ystep;   // how far through vertical expansion we are\n   int ypos;    // which pre-expansion row we're on\n} stbi__resample;\n\n// fast 0..255 * 0..255 => 0..255 rounded multiplication\nstatic stbi_uc stbi__blinn_8x8(stbi_uc x, stbi_uc y)\n{\n   unsigned int t = x*y + 128;\n   return (stbi_uc) ((t + (t >>8)) >> 8);\n}\n\nstatic stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)\n{\n   int n, decode_n, is_rgb;\n   z->s->img_n = 0; // make stbi__cleanup_jpeg safe\n\n   // validate req_comp\n   if (req_comp < 0 || req_comp > 4) return stbi__errpuc(\"bad req_comp\", \"Internal error\");\n\n   // load a jpeg image from whichever source, but leave in YCbCr format\n   if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }\n\n   // determine actual number of components to generate\n   n = req_comp ? req_comp : z->s->img_n >= 3 ? 3 : 1;\n\n   is_rgb = z->s->img_n == 3 && (z->rgb == 3 || (z->app14_color_transform == 0 && !z->jfif));\n\n   if (z->s->img_n == 3 && n < 3 && !is_rgb)\n      decode_n = 1;\n   else\n      decode_n = z->s->img_n;\n\n   // nothing to do if no components requested; check this now to avoid\n   // accessing uninitialized coutput[0] later\n   if (decode_n <= 0) { stbi__cleanup_jpeg(z); return NULL; }\n\n   // resample and color-convert\n   {\n      int k;\n      unsigned int i,j;\n      stbi_uc *output;\n      stbi_uc *coutput[4] = { NULL, NULL, NULL, NULL };\n\n      stbi__resample res_comp[4];\n\n      for (k=0; k < decode_n; ++k) {\n         stbi__resample *r = &res_comp[k];\n\n         // allocate line buffer big enough for upsampling off the edges\n         // with upsample factor of 4\n         z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);\n         if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n\n         r->hs      = z->img_h_max / z->img_comp[k].h;\n         r->vs      = z->img_v_max / z->img_comp[k].v;\n         r->ystep   = r->vs >> 1;\n         r->w_lores = (z->s->img_x + r->hs-1) / r->hs;\n         r->ypos    = 0;\n         r->line0   = r->line1 = z->img_comp[k].data;\n\n         if      (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;\n         else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;\n         else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;\n         else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;\n         else                               r->resample = stbi__resample_row_generic;\n      }\n\n      // can't error after this so, this is safe\n      output = (stbi_uc *) stbi__malloc_mad3(n, z->s->img_x, z->s->img_y, 1);\n      if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n\n      // now go ahead and resample\n      for (j=0; j < z->s->img_y; ++j) {\n         stbi_uc *out = output + n * z->s->img_x * j;\n         for (k=0; k < decode_n; ++k) {\n            stbi__resample *r = &res_comp[k];\n            int y_bot = r->ystep >= (r->vs >> 1);\n            coutput[k] = r->resample(z->img_comp[k].linebuf,\n                                     y_bot ? r->line1 : r->line0,\n                                     y_bot ? r->line0 : r->line1,\n                                     r->w_lores, r->hs);\n            if (++r->ystep >= r->vs) {\n               r->ystep = 0;\n               r->line0 = r->line1;\n               if (++r->ypos < z->img_comp[k].y)\n                  r->line1 += z->img_comp[k].w2;\n            }\n         }\n         if (n >= 3) {\n            stbi_uc *y = coutput[0];\n            if (z->s->img_n == 3) {\n               if (is_rgb) {\n                  for (i=0; i < z->s->img_x; ++i) {\n                     out[0] = y[i];\n                     out[1] = coutput[1][i];\n                     out[2] = coutput[2][i];\n                     out[3] = 255;\n                     out += n;\n                  }\n               } else {\n                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);\n               }\n            } else if (z->s->img_n == 4) {\n               if (z->app14_color_transform == 0) { // CMYK\n                  for (i=0; i < z->s->img_x; ++i) {\n                     stbi_uc m = coutput[3][i];\n                     out[0] = stbi__blinn_8x8(coutput[0][i], m);\n                     out[1] = stbi__blinn_8x8(coutput[1][i], m);\n                     out[2] = stbi__blinn_8x8(coutput[2][i], m);\n                     out[3] = 255;\n                     out += n;\n                  }\n               } else if (z->app14_color_transform == 2) { // YCCK\n                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);\n                  for (i=0; i < z->s->img_x; ++i) {\n                     stbi_uc m = coutput[3][i];\n                     out[0] = stbi__blinn_8x8(255 - out[0], m);\n                     out[1] = stbi__blinn_8x8(255 - out[1], m);\n                     out[2] = stbi__blinn_8x8(255 - out[2], m);\n                     out += n;\n                  }\n               } else { // YCbCr + alpha?  Ignore the fourth channel for now\n                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);\n               }\n            } else\n               for (i=0; i < z->s->img_x; ++i) {\n                  out[0] = out[1] = out[2] = y[i];\n                  out[3] = 255; // not used if n==3\n                  out += n;\n               }\n         } else {\n            if (is_rgb) {\n               if (n == 1)\n                  for (i=0; i < z->s->img_x; ++i)\n                     *out++ = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);\n               else {\n                  for (i=0; i < z->s->img_x; ++i, out += 2) {\n                     out[0] = stbi__compute_y(coutput[0][i], coutput[1][i], coutput[2][i]);\n                     out[1] = 255;\n                  }\n               }\n            } else if (z->s->img_n == 4 && z->app14_color_transform == 0) {\n               for (i=0; i < z->s->img_x; ++i) {\n                  stbi_uc m = coutput[3][i];\n                  stbi_uc r = stbi__blinn_8x8(coutput[0][i], m);\n                  stbi_uc g = stbi__blinn_8x8(coutput[1][i], m);\n                  stbi_uc b = stbi__blinn_8x8(coutput[2][i], m);\n                  out[0] = stbi__compute_y(r, g, b);\n                  out[1] = 255;\n                  out += n;\n               }\n            } else if (z->s->img_n == 4 && z->app14_color_transform == 2) {\n               for (i=0; i < z->s->img_x; ++i) {\n                  out[0] = stbi__blinn_8x8(255 - coutput[0][i], coutput[3][i]);\n                  out[1] = 255;\n                  out += n;\n               }\n            } else {\n               stbi_uc *y = coutput[0];\n               if (n == 1)\n                  for (i=0; i < z->s->img_x; ++i) out[i] = y[i];\n               else\n                  for (i=0; i < z->s->img_x; ++i) { *out++ = y[i]; *out++ = 255; }\n            }\n         }\n      }\n      stbi__cleanup_jpeg(z);\n      *out_x = z->s->img_x;\n      *out_y = z->s->img_y;\n      if (comp) *comp = z->s->img_n >= 3 ? 3 : 1; // report original components, not output\n      return output;\n   }\n}\n\nstatic void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   unsigned char* result;\n   stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));\n   if (!j) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   memset(j, 0, sizeof(stbi__jpeg));\n   STBI_NOTUSED(ri);\n   j->s = s;\n   stbi__setup_jpeg(j);\n   result = load_jpeg_image(j, x,y,comp,req_comp);\n   STBI_FREE(j);\n   return result;\n}\n\nstatic int stbi__jpeg_test(stbi__context *s)\n{\n   int r;\n   stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg));\n   if (!j) return stbi__err(\"outofmem\", \"Out of memory\");\n   memset(j, 0, sizeof(stbi__jpeg));\n   j->s = s;\n   stbi__setup_jpeg(j);\n   r = stbi__decode_jpeg_header(j, STBI__SCAN_type);\n   stbi__rewind(s);\n   STBI_FREE(j);\n   return r;\n}\n\nstatic int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)\n{\n   if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {\n      stbi__rewind( j->s );\n      return 0;\n   }\n   if (x) *x = j->s->img_x;\n   if (y) *y = j->s->img_y;\n   if (comp) *comp = j->s->img_n >= 3 ? 3 : 1;\n   return 1;\n}\n\nstatic int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int result;\n   stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));\n   if (!j) return stbi__err(\"outofmem\", \"Out of memory\");\n   memset(j, 0, sizeof(stbi__jpeg));\n   j->s = s;\n   result = stbi__jpeg_info_raw(j, x, y, comp);\n   STBI_FREE(j);\n   return result;\n}\n#endif\n\n// public domain zlib decode    v0.2  Sean Barrett 2006-11-18\n//    simple implementation\n//      - all input must be provided in an upfront buffer\n//      - all output is written to a single output buffer (can malloc/realloc)\n//    performance\n//      - fast huffman\n\n#ifndef STBI_NO_ZLIB\n\n// fast-way is faster to check than jpeg huffman, but slow way is slower\n#define STBI__ZFAST_BITS  9 // accelerate all cases in default tables\n#define STBI__ZFAST_MASK  ((1 << STBI__ZFAST_BITS) - 1)\n#define STBI__ZNSYMS 288 // number of symbols in literal/length alphabet\n\n// zlib-style huffman encoding\n// (jpegs packs from left, zlib from right, so can't share code)\ntypedef struct\n{\n   stbi__uint16 fast[1 << STBI__ZFAST_BITS];\n   stbi__uint16 firstcode[16];\n   int maxcode[17];\n   stbi__uint16 firstsymbol[16];\n   stbi_uc  size[STBI__ZNSYMS];\n   stbi__uint16 value[STBI__ZNSYMS];\n} stbi__zhuffman;\n\nstbi_inline static int stbi__bitreverse16(int n)\n{\n  n = ((n & 0xAAAA) >>  1) | ((n & 0x5555) << 1);\n  n = ((n & 0xCCCC) >>  2) | ((n & 0x3333) << 2);\n  n = ((n & 0xF0F0) >>  4) | ((n & 0x0F0F) << 4);\n  n = ((n & 0xFF00) >>  8) | ((n & 0x00FF) << 8);\n  return n;\n}\n\nstbi_inline static int stbi__bit_reverse(int v, int bits)\n{\n   STBI_ASSERT(bits <= 16);\n   // to bit reverse n bits, reverse 16 and shift\n   // e.g. 11 bits, bit reverse and shift away 5\n   return stbi__bitreverse16(v) >> (16-bits);\n}\n\nstatic int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num)\n{\n   int i,k=0;\n   int code, next_code[16], sizes[17];\n\n   // DEFLATE spec for generating codes\n   memset(sizes, 0, sizeof(sizes));\n   memset(z->fast, 0, sizeof(z->fast));\n   for (i=0; i < num; ++i)\n      ++sizes[sizelist[i]];\n   sizes[0] = 0;\n   for (i=1; i < 16; ++i)\n      if (sizes[i] > (1 << i))\n         return stbi__err(\"bad sizes\", \"Corrupt PNG\");\n   code = 0;\n   for (i=1; i < 16; ++i) {\n      next_code[i] = code;\n      z->firstcode[i] = (stbi__uint16) code;\n      z->firstsymbol[i] = (stbi__uint16) k;\n      code = (code + sizes[i]);\n      if (sizes[i])\n         if (code-1 >= (1 << i)) return stbi__err(\"bad codelengths\",\"Corrupt PNG\");\n      z->maxcode[i] = code << (16-i); // preshift for inner loop\n      code <<= 1;\n      k += sizes[i];\n   }\n   z->maxcode[16] = 0x10000; // sentinel\n   for (i=0; i < num; ++i) {\n      int s = sizelist[i];\n      if (s) {\n         int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];\n         stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);\n         z->size [c] = (stbi_uc     ) s;\n         z->value[c] = (stbi__uint16) i;\n         if (s <= STBI__ZFAST_BITS) {\n            int j = stbi__bit_reverse(next_code[s],s);\n            while (j < (1 << STBI__ZFAST_BITS)) {\n               z->fast[j] = fastv;\n               j += (1 << s);\n            }\n         }\n         ++next_code[s];\n      }\n   }\n   return 1;\n}\n\n// zlib-from-memory implementation for PNG reading\n//    because PNG allows splitting the zlib stream arbitrarily,\n//    and it's annoying structurally to have PNG call ZLIB call PNG,\n//    we require PNG read all the IDATs and combine them into a single\n//    memory buffer\n\ntypedef struct\n{\n   stbi_uc *zbuffer, *zbuffer_end;\n   int num_bits;\n   stbi__uint32 code_buffer;\n\n   char *zout;\n   char *zout_start;\n   char *zout_end;\n   int   z_expandable;\n\n   stbi__zhuffman z_length, z_distance;\n} stbi__zbuf;\n\nstbi_inline static int stbi__zeof(stbi__zbuf *z)\n{\n   return (z->zbuffer >= z->zbuffer_end);\n}\n\nstbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)\n{\n   return stbi__zeof(z) ? 0 : *z->zbuffer++;\n}\n\nstatic void stbi__fill_bits(stbi__zbuf *z)\n{\n   do {\n      if (z->code_buffer >= (1U << z->num_bits)) {\n        z->zbuffer = z->zbuffer_end;  /* treat this as EOF so we fail. */\n        return;\n      }\n      z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;\n      z->num_bits += 8;\n   } while (z->num_bits <= 24);\n}\n\nstbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)\n{\n   unsigned int k;\n   if (z->num_bits < n) stbi__fill_bits(z);\n   k = z->code_buffer & ((1 << n) - 1);\n   z->code_buffer >>= n;\n   z->num_bits -= n;\n   return k;\n}\n\nstatic int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)\n{\n   int b,s,k;\n   // not resolved by fast table, so compute it the slow way\n   // use jpeg approach, which requires MSbits at top\n   k = stbi__bit_reverse(a->code_buffer, 16);\n   for (s=STBI__ZFAST_BITS+1; ; ++s)\n      if (k < z->maxcode[s])\n         break;\n   if (s >= 16) return -1; // invalid code!\n   // code size is s, so:\n   b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];\n   if (b >= STBI__ZNSYMS) return -1; // some data was corrupt somewhere!\n   if (z->size[b] != s) return -1;  // was originally an assert, but report failure instead.\n   a->code_buffer >>= s;\n   a->num_bits -= s;\n   return z->value[b];\n}\n\nstbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)\n{\n   int b,s;\n   if (a->num_bits < 16) {\n      if (stbi__zeof(a)) {\n         return -1;   /* report error for unexpected end of data. */\n      }\n      stbi__fill_bits(a);\n   }\n   b = z->fast[a->code_buffer & STBI__ZFAST_MASK];\n   if (b) {\n      s = b >> 9;\n      a->code_buffer >>= s;\n      a->num_bits -= s;\n      return b & 511;\n   }\n   return stbi__zhuffman_decode_slowpath(a, z);\n}\n\nstatic int stbi__zexpand(stbi__zbuf *z, char *zout, int n)  // need to make room for n bytes\n{\n   char *q;\n   unsigned int cur, limit, old_limit;\n   z->zout = zout;\n   if (!z->z_expandable) return stbi__err(\"output buffer limit\",\"Corrupt PNG\");\n   cur   = (unsigned int) (z->zout - z->zout_start);\n   limit = old_limit = (unsigned) (z->zout_end - z->zout_start);\n   if (UINT_MAX - cur < (unsigned) n) return stbi__err(\"outofmem\", \"Out of memory\");\n   while (cur + n > limit) {\n      if(limit > UINT_MAX / 2) return stbi__err(\"outofmem\", \"Out of memory\");\n      limit *= 2;\n   }\n   q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);\n   STBI_NOTUSED(old_limit);\n   if (q == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n   z->zout_start = q;\n   z->zout       = q + cur;\n   z->zout_end   = q + limit;\n   return 1;\n}\n\nstatic const int stbi__zlength_base[31] = {\n   3,4,5,6,7,8,9,10,11,13,\n   15,17,19,23,27,31,35,43,51,59,\n   67,83,99,115,131,163,195,227,258,0,0 };\n\nstatic const int stbi__zlength_extra[31]=\n{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };\n\nstatic const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,\n257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};\n\nstatic const int stbi__zdist_extra[32] =\n{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};\n\nstatic int stbi__parse_huffman_block(stbi__zbuf *a)\n{\n   char *zout = a->zout;\n   for(;;) {\n      int z = stbi__zhuffman_decode(a, &a->z_length);\n      if (z < 256) {\n         if (z < 0) return stbi__err(\"bad huffman code\",\"Corrupt PNG\"); // error in huffman codes\n         if (zout >= a->zout_end) {\n            if (!stbi__zexpand(a, zout, 1)) return 0;\n            zout = a->zout;\n         }\n         *zout++ = (char) z;\n      } else {\n         stbi_uc *p;\n         int len,dist;\n         if (z == 256) {\n            a->zout = zout;\n            return 1;\n         }\n         if (z >= 286) return stbi__err(\"bad huffman code\",\"Corrupt PNG\"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data\n         z -= 257;\n         len = stbi__zlength_base[z];\n         if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);\n         z = stbi__zhuffman_decode(a, &a->z_distance);\n         if (z < 0 || z >= 30) return stbi__err(\"bad huffman code\",\"Corrupt PNG\"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data\n         dist = stbi__zdist_base[z];\n         if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);\n         if (zout - a->zout_start < dist) return stbi__err(\"bad dist\",\"Corrupt PNG\");\n         if (zout + len > a->zout_end) {\n            if (!stbi__zexpand(a, zout, len)) return 0;\n            zout = a->zout;\n         }\n         p = (stbi_uc *) (zout - dist);\n         if (dist == 1) { // run of one byte; common in images.\n            stbi_uc v = *p;\n            if (len) { do *zout++ = v; while (--len); }\n         } else {\n            if (len) { do *zout++ = *p++; while (--len); }\n         }\n      }\n   }\n}\n\nstatic int stbi__compute_huffman_codes(stbi__zbuf *a)\n{\n   static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };\n   stbi__zhuffman z_codelength;\n   stbi_uc lencodes[286+32+137];//padding for maximum single op\n   stbi_uc codelength_sizes[19];\n   int i,n;\n\n   int hlit  = stbi__zreceive(a,5) + 257;\n   int hdist = stbi__zreceive(a,5) + 1;\n   int hclen = stbi__zreceive(a,4) + 4;\n   int ntot  = hlit + hdist;\n\n   memset(codelength_sizes, 0, sizeof(codelength_sizes));\n   for (i=0; i < hclen; ++i) {\n      int s = stbi__zreceive(a,3);\n      codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;\n   }\n   if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;\n\n   n = 0;\n   while (n < ntot) {\n      int c = stbi__zhuffman_decode(a, &z_codelength);\n      if (c < 0 || c >= 19) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n      if (c < 16)\n         lencodes[n++] = (stbi_uc) c;\n      else {\n         stbi_uc fill = 0;\n         if (c == 16) {\n            c = stbi__zreceive(a,2)+3;\n            if (n == 0) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n            fill = lencodes[n-1];\n         } else if (c == 17) {\n            c = stbi__zreceive(a,3)+3;\n         } else if (c == 18) {\n            c = stbi__zreceive(a,7)+11;\n         } else {\n            return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n         }\n         if (ntot - n < c) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n         memset(lencodes+n, fill, c);\n         n += c;\n      }\n   }\n   if (n != ntot) return stbi__err(\"bad codelengths\",\"Corrupt PNG\");\n   if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;\n   if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;\n   return 1;\n}\n\nstatic int stbi__parse_uncompressed_block(stbi__zbuf *a)\n{\n   stbi_uc header[4];\n   int len,nlen,k;\n   if (a->num_bits & 7)\n      stbi__zreceive(a, a->num_bits & 7); // discard\n   // drain the bit-packed data into header\n   k = 0;\n   while (a->num_bits > 0) {\n      header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check\n      a->code_buffer >>= 8;\n      a->num_bits -= 8;\n   }\n   if (a->num_bits < 0) return stbi__err(\"zlib corrupt\",\"Corrupt PNG\");\n   // now fill header the normal way\n   while (k < 4)\n      header[k++] = stbi__zget8(a);\n   len  = header[1] * 256 + header[0];\n   nlen = header[3] * 256 + header[2];\n   if (nlen != (len ^ 0xffff)) return stbi__err(\"zlib corrupt\",\"Corrupt PNG\");\n   if (a->zbuffer + len > a->zbuffer_end) return stbi__err(\"read past buffer\",\"Corrupt PNG\");\n   if (a->zout + len > a->zout_end)\n      if (!stbi__zexpand(a, a->zout, len)) return 0;\n   memcpy(a->zout, a->zbuffer, len);\n   a->zbuffer += len;\n   a->zout += len;\n   return 1;\n}\n\nstatic int stbi__parse_zlib_header(stbi__zbuf *a)\n{\n   int cmf   = stbi__zget8(a);\n   int cm    = cmf & 15;\n   /* int cinfo = cmf >> 4; */\n   int flg   = stbi__zget8(a);\n   if (stbi__zeof(a)) return stbi__err(\"bad zlib header\",\"Corrupt PNG\"); // zlib spec\n   if ((cmf*256+flg) % 31 != 0) return stbi__err(\"bad zlib header\",\"Corrupt PNG\"); // zlib spec\n   if (flg & 32) return stbi__err(\"no preset dict\",\"Corrupt PNG\"); // preset dictionary not allowed in png\n   if (cm != 8) return stbi__err(\"bad compression\",\"Corrupt PNG\"); // DEFLATE required for png\n   // window = 1 << (8 + cinfo)... but who cares, we fully buffer output\n   return 1;\n}\n\nstatic const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] =\n{\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,\n   8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,\n   7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8\n};\nstatic const stbi_uc stbi__zdefault_distance[32] =\n{\n   5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5\n};\n/*\nInit algorithm:\n{\n   int i;   // use <= to match clearly with spec\n   for (i=0; i <= 143; ++i)     stbi__zdefault_length[i]   = 8;\n   for (   ; i <= 255; ++i)     stbi__zdefault_length[i]   = 9;\n   for (   ; i <= 279; ++i)     stbi__zdefault_length[i]   = 7;\n   for (   ; i <= 287; ++i)     stbi__zdefault_length[i]   = 8;\n\n   for (i=0; i <=  31; ++i)     stbi__zdefault_distance[i] = 5;\n}\n*/\n\nstatic int stbi__parse_zlib(stbi__zbuf *a, int parse_header)\n{\n   int final, type;\n   if (parse_header)\n      if (!stbi__parse_zlib_header(a)) return 0;\n   a->num_bits = 0;\n   a->code_buffer = 0;\n   do {\n      final = stbi__zreceive(a,1);\n      type = stbi__zreceive(a,2);\n      if (type == 0) {\n         if (!stbi__parse_uncompressed_block(a)) return 0;\n      } else if (type == 3) {\n         return 0;\n      } else {\n         if (type == 1) {\n            // use fixed code lengths\n            if (!stbi__zbuild_huffman(&a->z_length  , stbi__zdefault_length  , STBI__ZNSYMS)) return 0;\n            if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance,  32)) return 0;\n         } else {\n            if (!stbi__compute_huffman_codes(a)) return 0;\n         }\n         if (!stbi__parse_huffman_block(a)) return 0;\n      }\n   } while (!final);\n   return 1;\n}\n\nstatic int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)\n{\n   a->zout_start = obuf;\n   a->zout       = obuf;\n   a->zout_end   = obuf + olen;\n   a->z_expandable = exp;\n\n   return stbi__parse_zlib(a, parse_header);\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(initial_size);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer + len;\n   if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)\n{\n   return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(initial_size);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer + len;\n   if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)\n{\n   stbi__zbuf a;\n   a.zbuffer = (stbi_uc *) ibuffer;\n   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;\n   if (stbi__do_zlib(&a, obuffer, olen, 0, 1))\n      return (int) (a.zout - a.zout_start);\n   else\n      return -1;\n}\n\nSTBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(16384);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer+len;\n   if (stbi__do_zlib(&a, p, 16384, 1, 0)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)\n{\n   stbi__zbuf a;\n   a.zbuffer = (stbi_uc *) ibuffer;\n   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;\n   if (stbi__do_zlib(&a, obuffer, olen, 0, 0))\n      return (int) (a.zout - a.zout_start);\n   else\n      return -1;\n}\n#endif\n\n// public domain \"baseline\" PNG decoder   v0.10  Sean Barrett 2006-11-18\n//    simple implementation\n//      - only 8-bit samples\n//      - no CRC checking\n//      - allocates lots of intermediate memory\n//        - avoids problem of streaming data between subsystems\n//        - avoids explicit window management\n//    performance\n//      - uses stb_zlib, a PD zlib implementation with fast huffman decoding\n\n#ifndef STBI_NO_PNG\ntypedef struct\n{\n   stbi__uint32 length;\n   stbi__uint32 type;\n} stbi__pngchunk;\n\nstatic stbi__pngchunk stbi__get_chunk_header(stbi__context *s)\n{\n   stbi__pngchunk c;\n   c.length = stbi__get32be(s);\n   c.type   = stbi__get32be(s);\n   return c;\n}\n\nstatic int stbi__check_png_header(stbi__context *s)\n{\n   static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };\n   int i;\n   for (i=0; i < 8; ++i)\n      if (stbi__get8(s) != png_sig[i]) return stbi__err(\"bad png sig\",\"Not a PNG\");\n   return 1;\n}\n\ntypedef struct\n{\n   stbi__context *s;\n   stbi_uc *idata, *expanded, *out;\n   int depth;\n} stbi__png;\n\n\nenum {\n   STBI__F_none=0,\n   STBI__F_sub=1,\n   STBI__F_up=2,\n   STBI__F_avg=3,\n   STBI__F_paeth=4,\n   // synthetic filters used for first scanline to avoid needing a dummy row of 0s\n   STBI__F_avg_first,\n   STBI__F_paeth_first\n};\n\nstatic stbi_uc first_row_filter[5] =\n{\n   STBI__F_none,\n   STBI__F_sub,\n   STBI__F_none,\n   STBI__F_avg_first,\n   STBI__F_paeth_first\n};\n\nstatic int stbi__paeth(int a, int b, int c)\n{\n   int p = a + b - c;\n   int pa = abs(p-a);\n   int pb = abs(p-b);\n   int pc = abs(p-c);\n   if (pa <= pb && pa <= pc) return a;\n   if (pb <= pc) return b;\n   return c;\n}\n\nstatic const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };\n\n// create the png data from post-deflated data\nstatic int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)\n{\n   int bytes = (depth == 16? 2 : 1);\n   stbi__context *s = a->s;\n   stbi__uint32 i,j,stride = x*out_n*bytes;\n   stbi__uint32 img_len, img_width_bytes;\n   int k;\n   int img_n = s->img_n; // copy it into a local for later\n\n   int output_bytes = out_n*bytes;\n   int filter_bytes = img_n*bytes;\n   int width = x;\n\n   STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);\n   a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into\n   if (!a->out) return stbi__err(\"outofmem\", \"Out of memory\");\n\n   if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err(\"too large\", \"Corrupt PNG\");\n   img_width_bytes = (((img_n * x * depth) + 7) >> 3);\n   img_len = (img_width_bytes + 1) * y;\n\n   // we used to check for exact match between raw_len and img_len on non-interlaced PNGs,\n   // but issue #276 reported a PNG in the wild that had extra data at the end (all zeros),\n   // so just check for raw_len < img_len always.\n   if (raw_len < img_len) return stbi__err(\"not enough pixels\",\"Corrupt PNG\");\n\n   for (j=0; j < y; ++j) {\n      stbi_uc *cur = a->out + stride*j;\n      stbi_uc *prior;\n      int filter = *raw++;\n\n      if (filter > 4)\n         return stbi__err(\"invalid filter\",\"Corrupt PNG\");\n\n      if (depth < 8) {\n         if (img_width_bytes > x) return stbi__err(\"invalid width\",\"Corrupt PNG\");\n         cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place\n         filter_bytes = 1;\n         width = img_width_bytes;\n      }\n      prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above\n\n      // if first row, use special filter that doesn't sample previous row\n      if (j == 0) filter = first_row_filter[filter];\n\n      // handle first byte explicitly\n      for (k=0; k < filter_bytes; ++k) {\n         switch (filter) {\n            case STBI__F_none       : cur[k] = raw[k]; break;\n            case STBI__F_sub        : cur[k] = raw[k]; break;\n            case STBI__F_up         : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;\n            case STBI__F_avg        : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;\n            case STBI__F_paeth      : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;\n            case STBI__F_avg_first  : cur[k] = raw[k]; break;\n            case STBI__F_paeth_first: cur[k] = raw[k]; break;\n         }\n      }\n\n      if (depth == 8) {\n         if (img_n != out_n)\n            cur[img_n] = 255; // first pixel\n         raw += img_n;\n         cur += out_n;\n         prior += out_n;\n      } else if (depth == 16) {\n         if (img_n != out_n) {\n            cur[filter_bytes]   = 255; // first pixel top byte\n            cur[filter_bytes+1] = 255; // first pixel bottom byte\n         }\n         raw += filter_bytes;\n         cur += output_bytes;\n         prior += output_bytes;\n      } else {\n         raw += 1;\n         cur += 1;\n         prior += 1;\n      }\n\n      // this is a little gross, so that we don't switch per-pixel or per-component\n      if (depth < 8 || img_n == out_n) {\n         int nk = (width - 1)*filter_bytes;\n         #define STBI__CASE(f) \\\n             case f:     \\\n                for (k=0; k < nk; ++k)\n         switch (filter) {\n            // \"none\" filter turns into a memcpy here; make that explicit.\n            case STBI__F_none:         memcpy(cur, raw, nk); break;\n            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;\n            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;\n            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;\n            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;\n            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;\n            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;\n         }\n         #undef STBI__CASE\n         raw += nk;\n      } else {\n         STBI_ASSERT(img_n+1 == out_n);\n         #define STBI__CASE(f) \\\n             case f:     \\\n                for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \\\n                   for (k=0; k < filter_bytes; ++k)\n         switch (filter) {\n            STBI__CASE(STBI__F_none)         { cur[k] = raw[k]; } break;\n            STBI__CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;\n            STBI__CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;\n            STBI__CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;\n            STBI__CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;\n            STBI__CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;\n            STBI__CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;\n         }\n         #undef STBI__CASE\n\n         // the loop above sets the high byte of the pixels' alpha, but for\n         // 16 bit png files we also need the low byte set. we'll do that here.\n         if (depth == 16) {\n            cur = a->out + stride*j; // start at the beginning of the row again\n            for (i=0; i < x; ++i,cur+=output_bytes) {\n               cur[filter_bytes+1] = 255;\n            }\n         }\n      }\n   }\n\n   // we make a separate pass to expand bits to pixels; for performance,\n   // this could run two scanlines behind the above code, so it won't\n   // intefere with filtering but will still be in the cache.\n   if (depth < 8) {\n      for (j=0; j < y; ++j) {\n         stbi_uc *cur = a->out + stride*j;\n         stbi_uc *in  = a->out + stride*j + x*out_n - img_width_bytes;\n         // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit\n         // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop\n         stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range\n\n         // note that the final byte might overshoot and write more data than desired.\n         // we can allocate enough data that this never writes out of memory, but it\n         // could also overwrite the next scanline. can it overwrite non-empty data\n         // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.\n         // so we need to explicitly clamp the final ones\n\n         if (depth == 4) {\n            for (k=x*img_n; k >= 2; k-=2, ++in) {\n               *cur++ = scale * ((*in >> 4)       );\n               *cur++ = scale * ((*in     ) & 0x0f);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 4)       );\n         } else if (depth == 2) {\n            for (k=x*img_n; k >= 4; k-=4, ++in) {\n               *cur++ = scale * ((*in >> 6)       );\n               *cur++ = scale * ((*in >> 4) & 0x03);\n               *cur++ = scale * ((*in >> 2) & 0x03);\n               *cur++ = scale * ((*in     ) & 0x03);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 6)       );\n            if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);\n            if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);\n         } else if (depth == 1) {\n            for (k=x*img_n; k >= 8; k-=8, ++in) {\n               *cur++ = scale * ((*in >> 7)       );\n               *cur++ = scale * ((*in >> 6) & 0x01);\n               *cur++ = scale * ((*in >> 5) & 0x01);\n               *cur++ = scale * ((*in >> 4) & 0x01);\n               *cur++ = scale * ((*in >> 3) & 0x01);\n               *cur++ = scale * ((*in >> 2) & 0x01);\n               *cur++ = scale * ((*in >> 1) & 0x01);\n               *cur++ = scale * ((*in     ) & 0x01);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 7)       );\n            if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);\n            if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);\n            if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);\n            if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);\n            if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);\n            if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);\n         }\n         if (img_n != out_n) {\n            int q;\n            // insert alpha = 255\n            cur = a->out + stride*j;\n            if (img_n == 1) {\n               for (q=x-1; q >= 0; --q) {\n                  cur[q*2+1] = 255;\n                  cur[q*2+0] = cur[q];\n               }\n            } else {\n               STBI_ASSERT(img_n == 3);\n               for (q=x-1; q >= 0; --q) {\n                  cur[q*4+3] = 255;\n                  cur[q*4+2] = cur[q*3+2];\n                  cur[q*4+1] = cur[q*3+1];\n                  cur[q*4+0] = cur[q*3+0];\n               }\n            }\n         }\n      }\n   } else if (depth == 16) {\n      // force the image data from big-endian to platform-native.\n      // this is done in a separate pass due to the decoding relying\n      // on the data being untouched, but could probably be done\n      // per-line during decode if care is taken.\n      stbi_uc *cur = a->out;\n      stbi__uint16 *cur16 = (stbi__uint16*)cur;\n\n      for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {\n         *cur16 = (cur[0] << 8) | cur[1];\n      }\n   }\n\n   return 1;\n}\n\nstatic int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)\n{\n   int bytes = (depth == 16 ? 2 : 1);\n   int out_bytes = out_n * bytes;\n   stbi_uc *final;\n   int p;\n   if (!interlaced)\n      return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);\n\n   // de-interlacing\n   final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);\n   if (!final) return stbi__err(\"outofmem\", \"Out of memory\");\n   for (p=0; p < 7; ++p) {\n      int xorig[] = { 0,4,0,2,0,1,0 };\n      int yorig[] = { 0,0,4,0,2,0,1 };\n      int xspc[]  = { 8,8,4,4,2,2,1 };\n      int yspc[]  = { 8,8,8,4,4,2,2 };\n      int i,j,x,y;\n      // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1\n      x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];\n      y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];\n      if (x && y) {\n         stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;\n         if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {\n            STBI_FREE(final);\n            return 0;\n         }\n         for (j=0; j < y; ++j) {\n            for (i=0; i < x; ++i) {\n               int out_y = j*yspc[p]+yorig[p];\n               int out_x = i*xspc[p]+xorig[p];\n               memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,\n                      a->out + (j*x+i)*out_bytes, out_bytes);\n            }\n         }\n         STBI_FREE(a->out);\n         image_data += img_len;\n         image_data_len -= img_len;\n      }\n   }\n   a->out = final;\n\n   return 1;\n}\n\nstatic int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi_uc *p = z->out;\n\n   // compute color-based transparency, assuming we've\n   // already got 255 as the alpha value in the output\n   STBI_ASSERT(out_n == 2 || out_n == 4);\n\n   if (out_n == 2) {\n      for (i=0; i < pixel_count; ++i) {\n         p[1] = (p[0] == tc[0] ? 0 : 255);\n         p += 2;\n      }\n   } else {\n      for (i=0; i < pixel_count; ++i) {\n         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])\n            p[3] = 0;\n         p += 4;\n      }\n   }\n   return 1;\n}\n\nstatic int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi__uint16 *p = (stbi__uint16*) z->out;\n\n   // compute color-based transparency, assuming we've\n   // already got 65535 as the alpha value in the output\n   STBI_ASSERT(out_n == 2 || out_n == 4);\n\n   if (out_n == 2) {\n      for (i = 0; i < pixel_count; ++i) {\n         p[1] = (p[0] == tc[0] ? 0 : 65535);\n         p += 2;\n      }\n   } else {\n      for (i = 0; i < pixel_count; ++i) {\n         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])\n            p[3] = 0;\n         p += 4;\n      }\n   }\n   return 1;\n}\n\nstatic int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)\n{\n   stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;\n   stbi_uc *p, *temp_out, *orig = a->out;\n\n   p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);\n   if (p == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n\n   // between here and free(out) below, exitting would leak\n   temp_out = p;\n\n   if (pal_img_n == 3) {\n      for (i=0; i < pixel_count; ++i) {\n         int n = orig[i]*4;\n         p[0] = palette[n  ];\n         p[1] = palette[n+1];\n         p[2] = palette[n+2];\n         p += 3;\n      }\n   } else {\n      for (i=0; i < pixel_count; ++i) {\n         int n = orig[i]*4;\n         p[0] = palette[n  ];\n         p[1] = palette[n+1];\n         p[2] = palette[n+2];\n         p[3] = palette[n+3];\n         p += 4;\n      }\n   }\n   STBI_FREE(a->out);\n   a->out = temp_out;\n\n   STBI_NOTUSED(len);\n\n   return 1;\n}\n\nstatic int stbi__unpremultiply_on_load_global = 0;\nstatic int stbi__de_iphone_flag_global = 0;\n\nSTBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)\n{\n   stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply;\n}\n\nSTBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)\n{\n   stbi__de_iphone_flag_global = flag_true_if_should_convert;\n}\n\n#ifndef STBI_THREAD_LOCAL\n#define stbi__unpremultiply_on_load  stbi__unpremultiply_on_load_global\n#define stbi__de_iphone_flag  stbi__de_iphone_flag_global\n#else\nstatic STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set;\nstatic STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set;\n\nSTBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply)\n{\n   stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply;\n   stbi__unpremultiply_on_load_set = 1;\n}\n\nSTBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert)\n{\n   stbi__de_iphone_flag_local = flag_true_if_should_convert;\n   stbi__de_iphone_flag_set = 1;\n}\n\n#define stbi__unpremultiply_on_load  (stbi__unpremultiply_on_load_set           \\\n                                       ? stbi__unpremultiply_on_load_local      \\\n                                       : stbi__unpremultiply_on_load_global)\n#define stbi__de_iphone_flag  (stbi__de_iphone_flag_set                         \\\n                                ? stbi__de_iphone_flag_local                    \\\n                                : stbi__de_iphone_flag_global)\n#endif // STBI_THREAD_LOCAL\n\nstatic void stbi__de_iphone(stbi__png *z)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi_uc *p = z->out;\n\n   if (s->img_out_n == 3) {  // convert bgr to rgb\n      for (i=0; i < pixel_count; ++i) {\n         stbi_uc t = p[0];\n         p[0] = p[2];\n         p[2] = t;\n         p += 3;\n      }\n   } else {\n      STBI_ASSERT(s->img_out_n == 4);\n      if (stbi__unpremultiply_on_load) {\n         // convert bgr to rgb and unpremultiply\n         for (i=0; i < pixel_count; ++i) {\n            stbi_uc a = p[3];\n            stbi_uc t = p[0];\n            if (a) {\n               stbi_uc half = a / 2;\n               p[0] = (p[2] * 255 + half) / a;\n               p[1] = (p[1] * 255 + half) / a;\n               p[2] = ( t   * 255 + half) / a;\n            } else {\n               p[0] = p[2];\n               p[2] = t;\n            }\n            p += 4;\n         }\n      } else {\n         // convert bgr to rgb\n         for (i=0; i < pixel_count; ++i) {\n            stbi_uc t = p[0];\n            p[0] = p[2];\n            p[2] = t;\n            p += 4;\n         }\n      }\n   }\n}\n\n#define STBI__PNG_TYPE(a,b,c,d)  (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))\n\nstatic int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)\n{\n   stbi_uc palette[1024], pal_img_n=0;\n   stbi_uc has_trans=0, tc[3]={0};\n   stbi__uint16 tc16[3];\n   stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;\n   int first=1,k,interlace=0, color=0, is_iphone=0;\n   stbi__context *s = z->s;\n\n   z->expanded = NULL;\n   z->idata = NULL;\n   z->out = NULL;\n\n   if (!stbi__check_png_header(s)) return 0;\n\n   if (scan == STBI__SCAN_type) return 1;\n\n   for (;;) {\n      stbi__pngchunk c = stbi__get_chunk_header(s);\n      switch (c.type) {\n         case STBI__PNG_TYPE('C','g','B','I'):\n            is_iphone = 1;\n            stbi__skip(s, c.length);\n            break;\n         case STBI__PNG_TYPE('I','H','D','R'): {\n            int comp,filter;\n            if (!first) return stbi__err(\"multiple IHDR\",\"Corrupt PNG\");\n            first = 0;\n            if (c.length != 13) return stbi__err(\"bad IHDR len\",\"Corrupt PNG\");\n            s->img_x = stbi__get32be(s);\n            s->img_y = stbi__get32be(s);\n            if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n            if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n            z->depth = stbi__get8(s);  if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16)  return stbi__err(\"1/2/4/8/16-bit only\",\"PNG not supported: 1/2/4/8/16-bit only\");\n            color = stbi__get8(s);  if (color > 6)         return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            if (color == 3 && z->depth == 16)                  return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            comp  = stbi__get8(s);  if (comp) return stbi__err(\"bad comp method\",\"Corrupt PNG\");\n            filter= stbi__get8(s);  if (filter) return stbi__err(\"bad filter method\",\"Corrupt PNG\");\n            interlace = stbi__get8(s); if (interlace>1) return stbi__err(\"bad interlace method\",\"Corrupt PNG\");\n            if (!s->img_x || !s->img_y) return stbi__err(\"0-pixel image\",\"Corrupt PNG\");\n            if (!pal_img_n) {\n               s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);\n               if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err(\"too large\", \"Image too large to decode\");\n            } else {\n               // if paletted, then pal_n is our final components, and\n               // img_n is # components to decompress/filter.\n               s->img_n = 1;\n               if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err(\"too large\",\"Corrupt PNG\");\n            }\n            // even with SCAN_header, have to scan to see if we have a tRNS\n            break;\n         }\n\n         case STBI__PNG_TYPE('P','L','T','E'):  {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (c.length > 256*3) return stbi__err(\"invalid PLTE\",\"Corrupt PNG\");\n            pal_len = c.length / 3;\n            if (pal_len * 3 != c.length) return stbi__err(\"invalid PLTE\",\"Corrupt PNG\");\n            for (i=0; i < pal_len; ++i) {\n               palette[i*4+0] = stbi__get8(s);\n               palette[i*4+1] = stbi__get8(s);\n               palette[i*4+2] = stbi__get8(s);\n               palette[i*4+3] = 255;\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('t','R','N','S'): {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (z->idata) return stbi__err(\"tRNS after IDAT\",\"Corrupt PNG\");\n            if (pal_img_n) {\n               if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }\n               if (pal_len == 0) return stbi__err(\"tRNS before PLTE\",\"Corrupt PNG\");\n               if (c.length > pal_len) return stbi__err(\"bad tRNS len\",\"Corrupt PNG\");\n               pal_img_n = 4;\n               for (i=0; i < c.length; ++i)\n                  palette[i*4+3] = stbi__get8(s);\n            } else {\n               if (!(s->img_n & 1)) return stbi__err(\"tRNS with alpha\",\"Corrupt PNG\");\n               if (c.length != (stbi__uint32) s->img_n*2) return stbi__err(\"bad tRNS len\",\"Corrupt PNG\");\n               has_trans = 1;\n               // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now.\n               if (scan == STBI__SCAN_header) { ++s->img_n; return 1; }\n               if (z->depth == 16) {\n                  for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is\n               } else {\n                  for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger\n               }\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('I','D','A','T'): {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (pal_img_n && !pal_len) return stbi__err(\"no PLTE\",\"Corrupt PNG\");\n            if (scan == STBI__SCAN_header) {\n               // header scan definitely stops at first IDAT\n               if (pal_img_n)\n                  s->img_n = pal_img_n;\n               return 1;\n            }\n            if (c.length > (1u << 30)) return stbi__err(\"IDAT size limit\", \"IDAT section larger than 2^30 bytes\");\n            if ((int)(ioff + c.length) < (int)ioff) return 0;\n            if (ioff + c.length > idata_limit) {\n               stbi__uint32 idata_limit_old = idata_limit;\n               stbi_uc *p;\n               if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;\n               while (ioff + c.length > idata_limit)\n                  idata_limit *= 2;\n               STBI_NOTUSED(idata_limit_old);\n               p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n               z->idata = p;\n            }\n            if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err(\"outofdata\",\"Corrupt PNG\");\n            ioff += c.length;\n            break;\n         }\n\n         case STBI__PNG_TYPE('I','E','N','D'): {\n            stbi__uint32 raw_len, bpl;\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (scan != STBI__SCAN_load) return 1;\n            if (z->idata == NULL) return stbi__err(\"no IDAT\",\"Corrupt PNG\");\n            // initial guess for decoded data size to avoid unnecessary reallocs\n            bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component\n            raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;\n            z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);\n            if (z->expanded == NULL) return 0; // zlib should set error\n            STBI_FREE(z->idata); z->idata = NULL;\n            if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)\n               s->img_out_n = s->img_n+1;\n            else\n               s->img_out_n = s->img_n;\n            if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;\n            if (has_trans) {\n               if (z->depth == 16) {\n                  if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;\n               } else {\n                  if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;\n               }\n            }\n            if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)\n               stbi__de_iphone(z);\n            if (pal_img_n) {\n               // pal_img_n == 3 or 4\n               s->img_n = pal_img_n; // record the actual colors we had\n               s->img_out_n = pal_img_n;\n               if (req_comp >= 3) s->img_out_n = req_comp;\n               if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))\n                  return 0;\n            } else if (has_trans) {\n               // non-paletted image with tRNS -> source image has (constant) alpha\n               ++s->img_n;\n            }\n            STBI_FREE(z->expanded); z->expanded = NULL;\n            // end of PNG chunk, read and skip CRC\n            stbi__get32be(s);\n            return 1;\n         }\n\n         default:\n            // if critical, fail\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if ((c.type & (1 << 29)) == 0) {\n               #ifndef STBI_NO_FAILURE_STRINGS\n               // not threadsafe\n               static char invalid_chunk[] = \"XXXX PNG chunk not known\";\n               invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);\n               invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);\n               invalid_chunk[2] = STBI__BYTECAST(c.type >>  8);\n               invalid_chunk[3] = STBI__BYTECAST(c.type >>  0);\n               #endif\n               return stbi__err(invalid_chunk, \"PNG not supported: unknown PNG chunk type\");\n            }\n            stbi__skip(s, c.length);\n            break;\n      }\n      // end of PNG chunk, read and skip CRC\n      stbi__get32be(s);\n   }\n}\n\nstatic void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)\n{\n   void *result=NULL;\n   if (req_comp < 0 || req_comp > 4) return stbi__errpuc(\"bad req_comp\", \"Internal error\");\n   if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {\n      if (p->depth <= 8)\n         ri->bits_per_channel = 8;\n      else if (p->depth == 16)\n         ri->bits_per_channel = 16;\n      else\n         return stbi__errpuc(\"bad bits_per_channel\", \"PNG not supported: unsupported color depth\");\n      result = p->out;\n      p->out = NULL;\n      if (req_comp && req_comp != p->s->img_out_n) {\n         if (ri->bits_per_channel == 8)\n            result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);\n         else\n            result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);\n         p->s->img_out_n = req_comp;\n         if (result == NULL) return result;\n      }\n      *x = p->s->img_x;\n      *y = p->s->img_y;\n      if (n) *n = p->s->img_n;\n   }\n   STBI_FREE(p->out);      p->out      = NULL;\n   STBI_FREE(p->expanded); p->expanded = NULL;\n   STBI_FREE(p->idata);    p->idata    = NULL;\n\n   return result;\n}\n\nstatic void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi__png p;\n   p.s = s;\n   return stbi__do_png(&p, x,y,comp,req_comp, ri);\n}\n\nstatic int stbi__png_test(stbi__context *s)\n{\n   int r;\n   r = stbi__check_png_header(s);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)\n{\n   if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {\n      stbi__rewind( p->s );\n      return 0;\n   }\n   if (x) *x = p->s->img_x;\n   if (y) *y = p->s->img_y;\n   if (comp) *comp = p->s->img_n;\n   return 1;\n}\n\nstatic int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   stbi__png p;\n   p.s = s;\n   return stbi__png_info_raw(&p, x, y, comp);\n}\n\nstatic int stbi__png_is16(stbi__context *s)\n{\n   stbi__png p;\n   p.s = s;\n   if (!stbi__png_info_raw(&p, NULL, NULL, NULL))\n\t   return 0;\n   if (p.depth != 16) {\n      stbi__rewind(p.s);\n      return 0;\n   }\n   return 1;\n}\n#endif\n\n// Microsoft/Windows BMP image\n\n#ifndef STBI_NO_BMP\nstatic int stbi__bmp_test_raw(stbi__context *s)\n{\n   int r;\n   int sz;\n   if (stbi__get8(s) != 'B') return 0;\n   if (stbi__get8(s) != 'M') return 0;\n   stbi__get32le(s); // discard filesize\n   stbi__get16le(s); // discard reserved\n   stbi__get16le(s); // discard reserved\n   stbi__get32le(s); // discard data offset\n   sz = stbi__get32le(s);\n   r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);\n   return r;\n}\n\nstatic int stbi__bmp_test(stbi__context *s)\n{\n   int r = stbi__bmp_test_raw(s);\n   stbi__rewind(s);\n   return r;\n}\n\n\n// returns 0..31 for the highest set bit\nstatic int stbi__high_bit(unsigned int z)\n{\n   int n=0;\n   if (z == 0) return -1;\n   if (z >= 0x10000) { n += 16; z >>= 16; }\n   if (z >= 0x00100) { n +=  8; z >>=  8; }\n   if (z >= 0x00010) { n +=  4; z >>=  4; }\n   if (z >= 0x00004) { n +=  2; z >>=  2; }\n   if (z >= 0x00002) { n +=  1;/* >>=  1;*/ }\n   return n;\n}\n\nstatic int stbi__bitcount(unsigned int a)\n{\n   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); // max 2\n   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); // max 4\n   a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits\n   a = (a + (a >> 8)); // max 16 per 8 bits\n   a = (a + (a >> 16)); // max 32 per 8 bits\n   return a & 0xff;\n}\n\n// extract an arbitrarily-aligned N-bit value (N=bits)\n// from v, and then make it 8-bits long and fractionally\n// extend it to full full range.\nstatic int stbi__shiftsigned(unsigned int v, int shift, int bits)\n{\n   static unsigned int mul_table[9] = {\n      0,\n      0xff/*0b11111111*/, 0x55/*0b01010101*/, 0x49/*0b01001001*/, 0x11/*0b00010001*/,\n      0x21/*0b00100001*/, 0x41/*0b01000001*/, 0x81/*0b10000001*/, 0x01/*0b00000001*/,\n   };\n   static unsigned int shift_table[9] = {\n      0, 0,0,1,0,2,4,6,0,\n   };\n   if (shift < 0)\n      v <<= -shift;\n   else\n      v >>= shift;\n   STBI_ASSERT(v < 256);\n   v >>= (8-bits);\n   STBI_ASSERT(bits >= 0 && bits <= 8);\n   return (int) ((unsigned) v * mul_table[bits]) >> shift_table[bits];\n}\n\ntypedef struct\n{\n   int bpp, offset, hsz;\n   unsigned int mr,mg,mb,ma, all_a;\n   int extra_read;\n} stbi__bmp_data;\n\nstatic int stbi__bmp_set_mask_defaults(stbi__bmp_data *info, int compress)\n{\n   // BI_BITFIELDS specifies masks explicitly, don't override\n   if (compress == 3)\n      return 1;\n\n   if (compress == 0) {\n      if (info->bpp == 16) {\n         info->mr = 31u << 10;\n         info->mg = 31u <<  5;\n         info->mb = 31u <<  0;\n      } else if (info->bpp == 32) {\n         info->mr = 0xffu << 16;\n         info->mg = 0xffu <<  8;\n         info->mb = 0xffu <<  0;\n         info->ma = 0xffu << 24;\n         info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0\n      } else {\n         // otherwise, use defaults, which is all-0\n         info->mr = info->mg = info->mb = info->ma = 0;\n      }\n      return 1;\n   }\n   return 0; // error\n}\n\nstatic void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)\n{\n   int hsz;\n   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc(\"not BMP\", \"Corrupt BMP\");\n   stbi__get32le(s); // discard filesize\n   stbi__get16le(s); // discard reserved\n   stbi__get16le(s); // discard reserved\n   info->offset = stbi__get32le(s);\n   info->hsz = hsz = stbi__get32le(s);\n   info->mr = info->mg = info->mb = info->ma = 0;\n   info->extra_read = 14;\n\n   if (info->offset < 0) return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n\n   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc(\"unknown BMP\", \"BMP type not supported: unknown\");\n   if (hsz == 12) {\n      s->img_x = stbi__get16le(s);\n      s->img_y = stbi__get16le(s);\n   } else {\n      s->img_x = stbi__get32le(s);\n      s->img_y = stbi__get32le(s);\n   }\n   if (stbi__get16le(s) != 1) return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n   info->bpp = stbi__get16le(s);\n   if (hsz != 12) {\n      int compress = stbi__get32le(s);\n      if (compress == 1 || compress == 2) return stbi__errpuc(\"BMP RLE\", \"BMP type not supported: RLE\");\n      if (compress >= 4) return stbi__errpuc(\"BMP JPEG/PNG\", \"BMP type not supported: unsupported compression\"); // this includes PNG/JPEG modes\n      if (compress == 3 && info->bpp != 16 && info->bpp != 32) return stbi__errpuc(\"bad BMP\", \"bad BMP\"); // bitfields requires 16 or 32 bits/pixel\n      stbi__get32le(s); // discard sizeof\n      stbi__get32le(s); // discard hres\n      stbi__get32le(s); // discard vres\n      stbi__get32le(s); // discard colorsused\n      stbi__get32le(s); // discard max important\n      if (hsz == 40 || hsz == 56) {\n         if (hsz == 56) {\n            stbi__get32le(s);\n            stbi__get32le(s);\n            stbi__get32le(s);\n            stbi__get32le(s);\n         }\n         if (info->bpp == 16 || info->bpp == 32) {\n            if (compress == 0) {\n               stbi__bmp_set_mask_defaults(info, compress);\n            } else if (compress == 3) {\n               info->mr = stbi__get32le(s);\n               info->mg = stbi__get32le(s);\n               info->mb = stbi__get32le(s);\n               info->extra_read += 12;\n               // not documented, but generated by photoshop and handled by mspaint\n               if (info->mr == info->mg && info->mg == info->mb) {\n                  // ?!?!?\n                  return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n               }\n            } else\n               return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n         }\n      } else {\n         // V4/V5 header\n         int i;\n         if (hsz != 108 && hsz != 124)\n            return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n         info->mr = stbi__get32le(s);\n         info->mg = stbi__get32le(s);\n         info->mb = stbi__get32le(s);\n         info->ma = stbi__get32le(s);\n         if (compress != 3) // override mr/mg/mb unless in BI_BITFIELDS mode, as per docs\n            stbi__bmp_set_mask_defaults(info, compress);\n         stbi__get32le(s); // discard color space\n         for (i=0; i < 12; ++i)\n            stbi__get32le(s); // discard color space parameters\n         if (hsz == 124) {\n            stbi__get32le(s); // discard rendering intent\n            stbi__get32le(s); // discard offset of profile data\n            stbi__get32le(s); // discard size of profile data\n            stbi__get32le(s); // discard reserved\n         }\n      }\n   }\n   return (void *) 1;\n}\n\n\nstatic void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *out;\n   unsigned int mr=0,mg=0,mb=0,ma=0, all_a;\n   stbi_uc pal[256][4];\n   int psize=0,i,j,width;\n   int flip_vertically, pad, target;\n   stbi__bmp_data info;\n   STBI_NOTUSED(ri);\n\n   info.all_a = 255;\n   if (stbi__bmp_parse_header(s, &info) == NULL)\n      return NULL; // error code already set\n\n   flip_vertically = ((int) s->img_y) > 0;\n   s->img_y = abs((int) s->img_y);\n\n   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   mr = info.mr;\n   mg = info.mg;\n   mb = info.mb;\n   ma = info.ma;\n   all_a = info.all_a;\n\n   if (info.hsz == 12) {\n      if (info.bpp < 24)\n         psize = (info.offset - info.extra_read - 24) / 3;\n   } else {\n      if (info.bpp < 16)\n         psize = (info.offset - info.extra_read - info.hsz) >> 2;\n   }\n   if (psize == 0) {\n      // accept some number of extra bytes after the header, but if the offset points either to before\n      // the header ends or implies a large amount of extra data, reject the file as malformed\n      int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original);\n      int header_limit = 1024; // max we actually read is below 256 bytes currently.\n      int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size.\n      if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) {\n         return stbi__errpuc(\"bad header\", \"Corrupt BMP\");\n      }\n      // we established that bytes_read_so_far is positive and sensible.\n      // the first half of this test rejects offsets that are either too small positives, or\n      // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn\n      // ensures the number computed in the second half of the test can't overflow.\n      if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) {\n         return stbi__errpuc(\"bad offset\", \"Corrupt BMP\");\n      } else {\n         stbi__skip(s, info.offset - bytes_read_so_far);\n      }\n   }\n\n   if (info.bpp == 24 && ma == 0xff000000)\n      s->img_n = 3;\n   else\n      s->img_n = ma ? 4 : 3;\n   if (req_comp && req_comp >= 3) // we can directly decode 3 or 4\n      target = req_comp;\n   else\n      target = s->img_n; // if they want monochrome, we'll post-convert\n\n   // sanity-check size\n   if (!stbi__mad3sizes_valid(target, s->img_x, s->img_y, 0))\n      return stbi__errpuc(\"too large\", \"Corrupt BMP\");\n\n   out = (stbi_uc *) stbi__malloc_mad3(target, s->img_x, s->img_y, 0);\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   if (info.bpp < 16) {\n      int z=0;\n      if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc(\"invalid\", \"Corrupt BMP\"); }\n      for (i=0; i < psize; ++i) {\n         pal[i][2] = stbi__get8(s);\n         pal[i][1] = stbi__get8(s);\n         pal[i][0] = stbi__get8(s);\n         if (info.hsz != 12) stbi__get8(s);\n         pal[i][3] = 255;\n      }\n      stbi__skip(s, info.offset - info.extra_read - info.hsz - psize * (info.hsz == 12 ? 3 : 4));\n      if (info.bpp == 1) width = (s->img_x + 7) >> 3;\n      else if (info.bpp == 4) width = (s->img_x + 1) >> 1;\n      else if (info.bpp == 8) width = s->img_x;\n      else { STBI_FREE(out); return stbi__errpuc(\"bad bpp\", \"Corrupt BMP\"); }\n      pad = (-width)&3;\n      if (info.bpp == 1) {\n         for (j=0; j < (int) s->img_y; ++j) {\n            int bit_offset = 7, v = stbi__get8(s);\n            for (i=0; i < (int) s->img_x; ++i) {\n               int color = (v>>bit_offset)&0x1;\n               out[z++] = pal[color][0];\n               out[z++] = pal[color][1];\n               out[z++] = pal[color][2];\n               if (target == 4) out[z++] = 255;\n               if (i+1 == (int) s->img_x) break;\n               if((--bit_offset) < 0) {\n                  bit_offset = 7;\n                  v = stbi__get8(s);\n               }\n            }\n            stbi__skip(s, pad);\n         }\n      } else {\n         for (j=0; j < (int) s->img_y; ++j) {\n            for (i=0; i < (int) s->img_x; i += 2) {\n               int v=stbi__get8(s),v2=0;\n               if (info.bpp == 4) {\n                  v2 = v & 15;\n                  v >>= 4;\n               }\n               out[z++] = pal[v][0];\n               out[z++] = pal[v][1];\n               out[z++] = pal[v][2];\n               if (target == 4) out[z++] = 255;\n               if (i+1 == (int) s->img_x) break;\n               v = (info.bpp == 8) ? stbi__get8(s) : v2;\n               out[z++] = pal[v][0];\n               out[z++] = pal[v][1];\n               out[z++] = pal[v][2];\n               if (target == 4) out[z++] = 255;\n            }\n            stbi__skip(s, pad);\n         }\n      }\n   } else {\n      int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;\n      int z = 0;\n      int easy=0;\n      stbi__skip(s, info.offset - info.extra_read - info.hsz);\n      if (info.bpp == 24) width = 3 * s->img_x;\n      else if (info.bpp == 16) width = 2*s->img_x;\n      else /* bpp = 32 and pad = 0 */ width=0;\n      pad = (-width) & 3;\n      if (info.bpp == 24) {\n         easy = 1;\n      } else if (info.bpp == 32) {\n         if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)\n            easy = 2;\n      }\n      if (!easy) {\n         if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc(\"bad masks\", \"Corrupt BMP\"); }\n         // right shift amt to put high bit in position #7\n         rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);\n         gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);\n         bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);\n         ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);\n         if (rcount > 8 || gcount > 8 || bcount > 8 || acount > 8) { STBI_FREE(out); return stbi__errpuc(\"bad masks\", \"Corrupt BMP\"); }\n      }\n      for (j=0; j < (int) s->img_y; ++j) {\n         if (easy) {\n            for (i=0; i < (int) s->img_x; ++i) {\n               unsigned char a;\n               out[z+2] = stbi__get8(s);\n               out[z+1] = stbi__get8(s);\n               out[z+0] = stbi__get8(s);\n               z += 3;\n               a = (easy == 2 ? stbi__get8(s) : 255);\n               all_a |= a;\n               if (target == 4) out[z++] = a;\n            }\n         } else {\n            int bpp = info.bpp;\n            for (i=0; i < (int) s->img_x; ++i) {\n               stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));\n               unsigned int a;\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));\n               a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);\n               all_a |= a;\n               if (target == 4) out[z++] = STBI__BYTECAST(a);\n            }\n         }\n         stbi__skip(s, pad);\n      }\n   }\n\n   // if alpha channel is all 0s, replace with all 255s\n   if (target == 4 && all_a == 0)\n      for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4)\n         out[i] = 255;\n\n   if (flip_vertically) {\n      stbi_uc t;\n      for (j=0; j < (int) s->img_y>>1; ++j) {\n         stbi_uc *p1 = out +      j     *s->img_x*target;\n         stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;\n         for (i=0; i < (int) s->img_x*target; ++i) {\n            t = p1[i]; p1[i] = p2[i]; p2[i] = t;\n         }\n      }\n   }\n\n   if (req_comp && req_comp != target) {\n      out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n\n   *x = s->img_x;\n   *y = s->img_y;\n   if (comp) *comp = s->img_n;\n   return out;\n}\n#endif\n\n// Targa Truevision - TGA\n// by Jonathan Dummer\n#ifndef STBI_NO_TGA\n// returns STBI_rgb or whatever, 0 on error\nstatic int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)\n{\n   // only RGB or RGBA (incl. 16bit) or grey allowed\n   if (is_rgb16) *is_rgb16 = 0;\n   switch(bits_per_pixel) {\n      case 8:  return STBI_grey;\n      case 16: if(is_grey) return STBI_grey_alpha;\n               // fallthrough\n      case 15: if(is_rgb16) *is_rgb16 = 1;\n               return STBI_rgb;\n      case 24: // fallthrough\n      case 32: return bits_per_pixel/8;\n      default: return 0;\n   }\n}\n\nstatic int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)\n{\n    int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;\n    int sz, tga_colormap_type;\n    stbi__get8(s);                   // discard Offset\n    tga_colormap_type = stbi__get8(s); // colormap type\n    if( tga_colormap_type > 1 ) {\n        stbi__rewind(s);\n        return 0;      // only RGB or indexed allowed\n    }\n    tga_image_type = stbi__get8(s); // image type\n    if ( tga_colormap_type == 1 ) { // colormapped (paletted) image\n        if (tga_image_type != 1 && tga_image_type != 9) {\n            stbi__rewind(s);\n            return 0;\n        }\n        stbi__skip(s,4);       // skip index of first colormap entry and number of entries\n        sz = stbi__get8(s);    //   check bits per palette color entry\n        if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {\n            stbi__rewind(s);\n            return 0;\n        }\n        stbi__skip(s,4);       // skip image x and y origin\n        tga_colormap_bpp = sz;\n    } else { // \"normal\" image w/o colormap - only RGB or grey allowed, +/- RLE\n        if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {\n            stbi__rewind(s);\n            return 0; // only RGB or grey allowed, +/- RLE\n        }\n        stbi__skip(s,9); // skip colormap specification and image x/y origin\n        tga_colormap_bpp = 0;\n    }\n    tga_w = stbi__get16le(s);\n    if( tga_w < 1 ) {\n        stbi__rewind(s);\n        return 0;   // test width\n    }\n    tga_h = stbi__get16le(s);\n    if( tga_h < 1 ) {\n        stbi__rewind(s);\n        return 0;   // test height\n    }\n    tga_bits_per_pixel = stbi__get8(s); // bits per pixel\n    stbi__get8(s); // ignore alpha bits\n    if (tga_colormap_bpp != 0) {\n        if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {\n            // when using a colormap, tga_bits_per_pixel is the size of the indexes\n            // I don't think anything but 8 or 16bit indexes makes sense\n            stbi__rewind(s);\n            return 0;\n        }\n        tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);\n    } else {\n        tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);\n    }\n    if(!tga_comp) {\n      stbi__rewind(s);\n      return 0;\n    }\n    if (x) *x = tga_w;\n    if (y) *y = tga_h;\n    if (comp) *comp = tga_comp;\n    return 1;                   // seems to have passed everything\n}\n\nstatic int stbi__tga_test(stbi__context *s)\n{\n   int res = 0;\n   int sz, tga_color_type;\n   stbi__get8(s);      //   discard Offset\n   tga_color_type = stbi__get8(s);   //   color type\n   if ( tga_color_type > 1 ) goto errorEnd;   //   only RGB or indexed allowed\n   sz = stbi__get8(s);   //   image type\n   if ( tga_color_type == 1 ) { // colormapped (paletted) image\n      if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9\n      stbi__skip(s,4);       // skip index of first colormap entry and number of entries\n      sz = stbi__get8(s);    //   check bits per palette color entry\n      if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;\n      stbi__skip(s,4);       // skip image x and y origin\n   } else { // \"normal\" image w/o colormap\n      if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE\n      stbi__skip(s,9); // skip colormap specification and image x/y origin\n   }\n   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test width\n   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test height\n   sz = stbi__get8(s);   //   bits per pixel\n   if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index\n   if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;\n\n   res = 1; // if we got this far, everything's good and we can return 1 instead of 0\n\nerrorEnd:\n   stbi__rewind(s);\n   return res;\n}\n\n// read 16bit value and convert to 24bit RGB\nstatic void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)\n{\n   stbi__uint16 px = (stbi__uint16)stbi__get16le(s);\n   stbi__uint16 fiveBitMask = 31;\n   // we have 3 channels with 5bits each\n   int r = (px >> 10) & fiveBitMask;\n   int g = (px >> 5) & fiveBitMask;\n   int b = px & fiveBitMask;\n   // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later\n   out[0] = (stbi_uc)((r * 255)/31);\n   out[1] = (stbi_uc)((g * 255)/31);\n   out[2] = (stbi_uc)((b * 255)/31);\n\n   // some people claim that the most significant bit might be used for alpha\n   // (possibly if an alpha-bit is set in the \"image descriptor byte\")\n   // but that only made 16bit test images completely translucent..\n   // so let's treat all 15 and 16bit TGAs as RGB with no alpha.\n}\n\nstatic void *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   //   read in the TGA header stuff\n   int tga_offset = stbi__get8(s);\n   int tga_indexed = stbi__get8(s);\n   int tga_image_type = stbi__get8(s);\n   int tga_is_RLE = 0;\n   int tga_palette_start = stbi__get16le(s);\n   int tga_palette_len = stbi__get16le(s);\n   int tga_palette_bits = stbi__get8(s);\n   int tga_x_origin = stbi__get16le(s);\n   int tga_y_origin = stbi__get16le(s);\n   int tga_width = stbi__get16le(s);\n   int tga_height = stbi__get16le(s);\n   int tga_bits_per_pixel = stbi__get8(s);\n   int tga_comp, tga_rgb16=0;\n   int tga_inverted = stbi__get8(s);\n   // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)\n   //   image data\n   unsigned char *tga_data;\n   unsigned char *tga_palette = NULL;\n   int i, j;\n   unsigned char raw_data[4] = {0};\n   int RLE_count = 0;\n   int RLE_repeating = 0;\n   int read_next_pixel = 1;\n   STBI_NOTUSED(ri);\n   STBI_NOTUSED(tga_x_origin); // @TODO\n   STBI_NOTUSED(tga_y_origin); // @TODO\n\n   if (tga_height > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (tga_width > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   //   do a tiny bit of precessing\n   if ( tga_image_type >= 8 )\n   {\n      tga_image_type -= 8;\n      tga_is_RLE = 1;\n   }\n   tga_inverted = 1 - ((tga_inverted >> 5) & 1);\n\n   //   If I'm paletted, then I'll use the number of bits from the palette\n   if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);\n   else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);\n\n   if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency\n      return stbi__errpuc(\"bad format\", \"Can't find out TGA pixelformat\");\n\n   //   tga info\n   *x = tga_width;\n   *y = tga_height;\n   if (comp) *comp = tga_comp;\n\n   if (!stbi__mad3sizes_valid(tga_width, tga_height, tga_comp, 0))\n      return stbi__errpuc(\"too large\", \"Corrupt TGA\");\n\n   tga_data = (unsigned char*)stbi__malloc_mad3(tga_width, tga_height, tga_comp, 0);\n   if (!tga_data) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   // skip to the data's starting position (offset usually = 0)\n   stbi__skip(s, tga_offset );\n\n   if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {\n      for (i=0; i < tga_height; ++i) {\n         int row = tga_inverted ? tga_height -i - 1 : i;\n         stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;\n         stbi__getn(s, tga_row, tga_width * tga_comp);\n      }\n   } else  {\n      //   do I need to load a palette?\n      if ( tga_indexed)\n      {\n         if (tga_palette_len == 0) {  /* you have to have at least one entry! */\n            STBI_FREE(tga_data);\n            return stbi__errpuc(\"bad palette\", \"Corrupt TGA\");\n         }\n\n         //   any data to skip? (offset usually = 0)\n         stbi__skip(s, tga_palette_start );\n         //   load the palette\n         tga_palette = (unsigned char*)stbi__malloc_mad2(tga_palette_len, tga_comp, 0);\n         if (!tga_palette) {\n            STBI_FREE(tga_data);\n            return stbi__errpuc(\"outofmem\", \"Out of memory\");\n         }\n         if (tga_rgb16) {\n            stbi_uc *pal_entry = tga_palette;\n            STBI_ASSERT(tga_comp == STBI_rgb);\n            for (i=0; i < tga_palette_len; ++i) {\n               stbi__tga_read_rgb16(s, pal_entry);\n               pal_entry += tga_comp;\n            }\n         } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {\n               STBI_FREE(tga_data);\n               STBI_FREE(tga_palette);\n               return stbi__errpuc(\"bad palette\", \"Corrupt TGA\");\n         }\n      }\n      //   load the data\n      for (i=0; i < tga_width * tga_height; ++i)\n      {\n         //   if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?\n         if ( tga_is_RLE )\n         {\n            if ( RLE_count == 0 )\n            {\n               //   yep, get the next byte as a RLE command\n               int RLE_cmd = stbi__get8(s);\n               RLE_count = 1 + (RLE_cmd & 127);\n               RLE_repeating = RLE_cmd >> 7;\n               read_next_pixel = 1;\n            } else if ( !RLE_repeating )\n            {\n               read_next_pixel = 1;\n            }\n         } else\n         {\n            read_next_pixel = 1;\n         }\n         //   OK, if I need to read a pixel, do it now\n         if ( read_next_pixel )\n         {\n            //   load however much data we did have\n            if ( tga_indexed )\n            {\n               // read in index, then perform the lookup\n               int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);\n               if ( pal_idx >= tga_palette_len ) {\n                  // invalid index\n                  pal_idx = 0;\n               }\n               pal_idx *= tga_comp;\n               for (j = 0; j < tga_comp; ++j) {\n                  raw_data[j] = tga_palette[pal_idx+j];\n               }\n            } else if(tga_rgb16) {\n               STBI_ASSERT(tga_comp == STBI_rgb);\n               stbi__tga_read_rgb16(s, raw_data);\n            } else {\n               //   read in the data raw\n               for (j = 0; j < tga_comp; ++j) {\n                  raw_data[j] = stbi__get8(s);\n               }\n            }\n            //   clear the reading flag for the next pixel\n            read_next_pixel = 0;\n         } // end of reading a pixel\n\n         // copy data\n         for (j = 0; j < tga_comp; ++j)\n           tga_data[i*tga_comp+j] = raw_data[j];\n\n         //   in case we're in RLE mode, keep counting down\n         --RLE_count;\n      }\n      //   do I need to invert the image?\n      if ( tga_inverted )\n      {\n         for (j = 0; j*2 < tga_height; ++j)\n         {\n            int index1 = j * tga_width * tga_comp;\n            int index2 = (tga_height - 1 - j) * tga_width * tga_comp;\n            for (i = tga_width * tga_comp; i > 0; --i)\n            {\n               unsigned char temp = tga_data[index1];\n               tga_data[index1] = tga_data[index2];\n               tga_data[index2] = temp;\n               ++index1;\n               ++index2;\n            }\n         }\n      }\n      //   clear my palette, if I had one\n      if ( tga_palette != NULL )\n      {\n         STBI_FREE( tga_palette );\n      }\n   }\n\n   // swap RGB - if the source data was RGB16, it already is in the right order\n   if (tga_comp >= 3 && !tga_rgb16)\n   {\n      unsigned char* tga_pixel = tga_data;\n      for (i=0; i < tga_width * tga_height; ++i)\n      {\n         unsigned char temp = tga_pixel[0];\n         tga_pixel[0] = tga_pixel[2];\n         tga_pixel[2] = temp;\n         tga_pixel += tga_comp;\n      }\n   }\n\n   // convert to target component count\n   if (req_comp && req_comp != tga_comp)\n      tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);\n\n   //   the things I do to get rid of an error message, and yet keep\n   //   Microsoft's C compilers happy... [8^(\n   tga_palette_start = tga_palette_len = tga_palette_bits =\n         tga_x_origin = tga_y_origin = 0;\n   STBI_NOTUSED(tga_palette_start);\n   //   OK, done\n   return tga_data;\n}\n#endif\n\n// *************************************************************************************************\n// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB\n\n#ifndef STBI_NO_PSD\nstatic int stbi__psd_test(stbi__context *s)\n{\n   int r = (stbi__get32be(s) == 0x38425053);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic int stbi__psd_decode_rle(stbi__context *s, stbi_uc *p, int pixelCount)\n{\n   int count, nleft, len;\n\n   count = 0;\n   while ((nleft = pixelCount - count) > 0) {\n      len = stbi__get8(s);\n      if (len == 128) {\n         // No-op.\n      } else if (len < 128) {\n         // Copy next len+1 bytes literally.\n         len++;\n         if (len > nleft) return 0; // corrupt data\n         count += len;\n         while (len) {\n            *p = stbi__get8(s);\n            p += 4;\n            len--;\n         }\n      } else if (len > 128) {\n         stbi_uc   val;\n         // Next -len+1 bytes in the dest are replicated from next source byte.\n         // (Interpret len as a negative 8-bit int.)\n         len = 257 - len;\n         if (len > nleft) return 0; // corrupt data\n         val = stbi__get8(s);\n         count += len;\n         while (len) {\n            *p = val;\n            p += 4;\n            len--;\n         }\n      }\n   }\n\n   return 1;\n}\n\nstatic void *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)\n{\n   int pixelCount;\n   int channelCount, compression;\n   int channel, i;\n   int bitdepth;\n   int w,h;\n   stbi_uc *out;\n   STBI_NOTUSED(ri);\n\n   // Check identifier\n   if (stbi__get32be(s) != 0x38425053)   // \"8BPS\"\n      return stbi__errpuc(\"not PSD\", \"Corrupt PSD image\");\n\n   // Check file type version.\n   if (stbi__get16be(s) != 1)\n      return stbi__errpuc(\"wrong version\", \"Unsupported version of PSD image\");\n\n   // Skip 6 reserved bytes.\n   stbi__skip(s, 6 );\n\n   // Read the number of channels (R, G, B, A, etc).\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16)\n      return stbi__errpuc(\"wrong channel count\", \"Unsupported number of channels in PSD image\");\n\n   // Read the rows and columns of the image.\n   h = stbi__get32be(s);\n   w = stbi__get32be(s);\n\n   if (h > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (w > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   // Make sure the depth is 8 bits.\n   bitdepth = stbi__get16be(s);\n   if (bitdepth != 8 && bitdepth != 16)\n      return stbi__errpuc(\"unsupported bit depth\", \"PSD bit depth is not 8 or 16 bit\");\n\n   // Make sure the color mode is RGB.\n   // Valid options are:\n   //   0: Bitmap\n   //   1: Grayscale\n   //   2: Indexed color\n   //   3: RGB color\n   //   4: CMYK color\n   //   7: Multichannel\n   //   8: Duotone\n   //   9: Lab color\n   if (stbi__get16be(s) != 3)\n      return stbi__errpuc(\"wrong color format\", \"PSD is not in RGB color format\");\n\n   // Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)\n   stbi__skip(s,stbi__get32be(s) );\n\n   // Skip the image resources.  (resolution, pen tool paths, etc)\n   stbi__skip(s, stbi__get32be(s) );\n\n   // Skip the reserved data.\n   stbi__skip(s, stbi__get32be(s) );\n\n   // Find out if the data is compressed.\n   // Known values:\n   //   0: no compression\n   //   1: RLE compressed\n   compression = stbi__get16be(s);\n   if (compression > 1)\n      return stbi__errpuc(\"bad compression\", \"PSD has an unknown compression format\");\n\n   // Check size\n   if (!stbi__mad3sizes_valid(4, w, h, 0))\n      return stbi__errpuc(\"too large\", \"Corrupt PSD\");\n\n   // Create the destination image.\n\n   if (!compression && bitdepth == 16 && bpc == 16) {\n      out = (stbi_uc *) stbi__malloc_mad3(8, w, h, 0);\n      ri->bits_per_channel = 16;\n   } else\n      out = (stbi_uc *) stbi__malloc(4 * w*h);\n\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   pixelCount = w*h;\n\n   // Initialize the data to zero.\n   //memset( out, 0, pixelCount * 4 );\n\n   // Finally, the image data.\n   if (compression) {\n      // RLE as used by .PSD and .TIFF\n      // Loop until you get the number of unpacked bytes you are expecting:\n      //     Read the next source byte into n.\n      //     If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.\n      //     Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.\n      //     Else if n is 128, noop.\n      // Endloop\n\n      // The RLE-compressed data is preceded by a 2-byte data count for each row in the data,\n      // which we're going to just skip.\n      stbi__skip(s, h * channelCount * 2 );\n\n      // Read the RLE data by channel.\n      for (channel = 0; channel < 4; channel++) {\n         stbi_uc *p;\n\n         p = out+channel;\n         if (channel >= channelCount) {\n            // Fill this channel with default data.\n            for (i = 0; i < pixelCount; i++, p += 4)\n               *p = (channel == 3 ? 255 : 0);\n         } else {\n            // Read the RLE data.\n            if (!stbi__psd_decode_rle(s, p, pixelCount)) {\n               STBI_FREE(out);\n               return stbi__errpuc(\"corrupt\", \"bad RLE data\");\n            }\n         }\n      }\n\n   } else {\n      // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)\n      // where each channel consists of an 8-bit (or 16-bit) value for each pixel in the image.\n\n      // Read the data by channel.\n      for (channel = 0; channel < 4; channel++) {\n         if (channel >= channelCount) {\n            // Fill this channel with default data.\n            if (bitdepth == 16 && bpc == 16) {\n               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;\n               stbi__uint16 val = channel == 3 ? 65535 : 0;\n               for (i = 0; i < pixelCount; i++, q += 4)\n                  *q = val;\n            } else {\n               stbi_uc *p = out+channel;\n               stbi_uc val = channel == 3 ? 255 : 0;\n               for (i = 0; i < pixelCount; i++, p += 4)\n                  *p = val;\n            }\n         } else {\n            if (ri->bits_per_channel == 16) {    // output bpc\n               stbi__uint16 *q = ((stbi__uint16 *) out) + channel;\n               for (i = 0; i < pixelCount; i++, q += 4)\n                  *q = (stbi__uint16) stbi__get16be(s);\n            } else {\n               stbi_uc *p = out+channel;\n               if (bitdepth == 16) {  // input bpc\n                  for (i = 0; i < pixelCount; i++, p += 4)\n                     *p = (stbi_uc) (stbi__get16be(s) >> 8);\n               } else {\n                  for (i = 0; i < pixelCount; i++, p += 4)\n                     *p = stbi__get8(s);\n               }\n            }\n         }\n      }\n   }\n\n   // remove weird white matte from PSD\n   if (channelCount >= 4) {\n      if (ri->bits_per_channel == 16) {\n         for (i=0; i < w*h; ++i) {\n            stbi__uint16 *pixel = (stbi__uint16 *) out + 4*i;\n            if (pixel[3] != 0 && pixel[3] != 65535) {\n               float a = pixel[3] / 65535.0f;\n               float ra = 1.0f / a;\n               float inv_a = 65535.0f * (1 - ra);\n               pixel[0] = (stbi__uint16) (pixel[0]*ra + inv_a);\n               pixel[1] = (stbi__uint16) (pixel[1]*ra + inv_a);\n               pixel[2] = (stbi__uint16) (pixel[2]*ra + inv_a);\n            }\n         }\n      } else {\n         for (i=0; i < w*h; ++i) {\n            unsigned char *pixel = out + 4*i;\n            if (pixel[3] != 0 && pixel[3] != 255) {\n               float a = pixel[3] / 255.0f;\n               float ra = 1.0f / a;\n               float inv_a = 255.0f * (1 - ra);\n               pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);\n               pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);\n               pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);\n            }\n         }\n      }\n   }\n\n   // convert to desired output format\n   if (req_comp && req_comp != 4) {\n      if (ri->bits_per_channel == 16)\n         out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, 4, req_comp, w, h);\n      else\n         out = stbi__convert_format(out, 4, req_comp, w, h);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n\n   if (comp) *comp = 4;\n   *y = h;\n   *x = w;\n\n   return out;\n}\n#endif\n\n// *************************************************************************************************\n// Softimage PIC loader\n// by Tom Seddon\n//\n// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format\n// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/\n\n#ifndef STBI_NO_PIC\nstatic int stbi__pic_is4(stbi__context *s,const char *str)\n{\n   int i;\n   for (i=0; i<4; ++i)\n      if (stbi__get8(s) != (stbi_uc)str[i])\n         return 0;\n\n   return 1;\n}\n\nstatic int stbi__pic_test_core(stbi__context *s)\n{\n   int i;\n\n   if (!stbi__pic_is4(s,\"\\x53\\x80\\xF6\\x34\"))\n      return 0;\n\n   for(i=0;i<84;++i)\n      stbi__get8(s);\n\n   if (!stbi__pic_is4(s,\"PICT\"))\n      return 0;\n\n   return 1;\n}\n\ntypedef struct\n{\n   stbi_uc size,type,channel;\n} stbi__pic_packet;\n\nstatic stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)\n{\n   int mask=0x80, i;\n\n   for (i=0; i<4; ++i, mask>>=1) {\n      if (channel & mask) {\n         if (stbi__at_eof(s)) return stbi__errpuc(\"bad file\",\"PIC file too short\");\n         dest[i]=stbi__get8(s);\n      }\n   }\n\n   return dest;\n}\n\nstatic void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)\n{\n   int mask=0x80,i;\n\n   for (i=0;i<4; ++i, mask>>=1)\n      if (channel&mask)\n         dest[i]=src[i];\n}\n\nstatic stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)\n{\n   int act_comp=0,num_packets=0,y,chained;\n   stbi__pic_packet packets[10];\n\n   // this will (should...) cater for even some bizarre stuff like having data\n    // for the same channel in multiple packets.\n   do {\n      stbi__pic_packet *packet;\n\n      if (num_packets==sizeof(packets)/sizeof(packets[0]))\n         return stbi__errpuc(\"bad format\",\"too many packets\");\n\n      packet = &packets[num_packets++];\n\n      chained = stbi__get8(s);\n      packet->size    = stbi__get8(s);\n      packet->type    = stbi__get8(s);\n      packet->channel = stbi__get8(s);\n\n      act_comp |= packet->channel;\n\n      if (stbi__at_eof(s))          return stbi__errpuc(\"bad file\",\"file too short (reading packets)\");\n      if (packet->size != 8)  return stbi__errpuc(\"bad format\",\"packet isn't 8bpp\");\n   } while (chained);\n\n   *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?\n\n   for(y=0; y<height; ++y) {\n      int packet_idx;\n\n      for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {\n         stbi__pic_packet *packet = &packets[packet_idx];\n         stbi_uc *dest = result+y*width*4;\n\n         switch (packet->type) {\n            default:\n               return stbi__errpuc(\"bad format\",\"packet has bad compression type\");\n\n            case 0: {//uncompressed\n               int x;\n\n               for(x=0;x<width;++x, dest+=4)\n                  if (!stbi__readval(s,packet->channel,dest))\n                     return 0;\n               break;\n            }\n\n            case 1://Pure RLE\n               {\n                  int left=width, i;\n\n                  while (left>0) {\n                     stbi_uc count,value[4];\n\n                     count=stbi__get8(s);\n                     if (stbi__at_eof(s))   return stbi__errpuc(\"bad file\",\"file too short (pure read count)\");\n\n                     if (count > left)\n                        count = (stbi_uc) left;\n\n                     if (!stbi__readval(s,packet->channel,value))  return 0;\n\n                     for(i=0; i<count; ++i,dest+=4)\n                        stbi__copyval(packet->channel,dest,value);\n                     left -= count;\n                  }\n               }\n               break;\n\n            case 2: {//Mixed RLE\n               int left=width;\n               while (left>0) {\n                  int count = stbi__get8(s), i;\n                  if (stbi__at_eof(s))  return stbi__errpuc(\"bad file\",\"file too short (mixed read count)\");\n\n                  if (count >= 128) { // Repeated\n                     stbi_uc value[4];\n\n                     if (count==128)\n                        count = stbi__get16be(s);\n                     else\n                        count -= 127;\n                     if (count > left)\n                        return stbi__errpuc(\"bad file\",\"scanline overrun\");\n\n                     if (!stbi__readval(s,packet->channel,value))\n                        return 0;\n\n                     for(i=0;i<count;++i, dest += 4)\n                        stbi__copyval(packet->channel,dest,value);\n                  } else { // Raw\n                     ++count;\n                     if (count>left) return stbi__errpuc(\"bad file\",\"scanline overrun\");\n\n                     for(i=0;i<count;++i, dest+=4)\n                        if (!stbi__readval(s,packet->channel,dest))\n                           return 0;\n                  }\n                  left-=count;\n               }\n               break;\n            }\n         }\n      }\n   }\n\n   return result;\n}\n\nstatic void *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *result;\n   int i, x,y, internal_comp;\n   STBI_NOTUSED(ri);\n\n   if (!comp) comp = &internal_comp;\n\n   for (i=0; i<92; ++i)\n      stbi__get8(s);\n\n   x = stbi__get16be(s);\n   y = stbi__get16be(s);\n\n   if (y > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (x > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   if (stbi__at_eof(s))  return stbi__errpuc(\"bad file\",\"file too short (pic header)\");\n   if (!stbi__mad3sizes_valid(x, y, 4, 0)) return stbi__errpuc(\"too large\", \"PIC image too large to decode\");\n\n   stbi__get32be(s); //skip `ratio'\n   stbi__get16be(s); //skip `fields'\n   stbi__get16be(s); //skip `pad'\n\n   // intermediate buffer is RGBA\n   result = (stbi_uc *) stbi__malloc_mad3(x, y, 4, 0);\n   if (!result) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   memset(result, 0xff, x*y*4);\n\n   if (!stbi__pic_load_core(s,x,y,comp, result)) {\n      STBI_FREE(result);\n      result=0;\n   }\n   *px = x;\n   *py = y;\n   if (req_comp == 0) req_comp = *comp;\n   result=stbi__convert_format(result,4,req_comp,x,y);\n\n   return result;\n}\n\nstatic int stbi__pic_test(stbi__context *s)\n{\n   int r = stbi__pic_test_core(s);\n   stbi__rewind(s);\n   return r;\n}\n#endif\n\n// *************************************************************************************************\n// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb\n\n#ifndef STBI_NO_GIF\ntypedef struct\n{\n   stbi__int16 prefix;\n   stbi_uc first;\n   stbi_uc suffix;\n} stbi__gif_lzw;\n\ntypedef struct\n{\n   int w,h;\n   stbi_uc *out;                 // output buffer (always 4 components)\n   stbi_uc *background;          // The current \"background\" as far as a gif is concerned\n   stbi_uc *history;\n   int flags, bgindex, ratio, transparent, eflags;\n   stbi_uc  pal[256][4];\n   stbi_uc lpal[256][4];\n   stbi__gif_lzw codes[8192];\n   stbi_uc *color_table;\n   int parse, step;\n   int lflags;\n   int start_x, start_y;\n   int max_x, max_y;\n   int cur_x, cur_y;\n   int line_size;\n   int delay;\n} stbi__gif;\n\nstatic int stbi__gif_test_raw(stbi__context *s)\n{\n   int sz;\n   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;\n   sz = stbi__get8(s);\n   if (sz != '9' && sz != '7') return 0;\n   if (stbi__get8(s) != 'a') return 0;\n   return 1;\n}\n\nstatic int stbi__gif_test(stbi__context *s)\n{\n   int r = stbi__gif_test_raw(s);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)\n{\n   int i;\n   for (i=0; i < num_entries; ++i) {\n      pal[i][2] = stbi__get8(s);\n      pal[i][1] = stbi__get8(s);\n      pal[i][0] = stbi__get8(s);\n      pal[i][3] = transp == i ? 0 : 255;\n   }\n}\n\nstatic int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)\n{\n   stbi_uc version;\n   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')\n      return stbi__err(\"not GIF\", \"Corrupt GIF\");\n\n   version = stbi__get8(s);\n   if (version != '7' && version != '9')    return stbi__err(\"not GIF\", \"Corrupt GIF\");\n   if (stbi__get8(s) != 'a')                return stbi__err(\"not GIF\", \"Corrupt GIF\");\n\n   stbi__g_failure_reason = \"\";\n   g->w = stbi__get16le(s);\n   g->h = stbi__get16le(s);\n   g->flags = stbi__get8(s);\n   g->bgindex = stbi__get8(s);\n   g->ratio = stbi__get8(s);\n   g->transparent = -1;\n\n   if (g->w > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n   if (g->h > STBI_MAX_DIMENSIONS) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n\n   if (comp != 0) *comp = 4;  // can't actually tell whether it's 3 or 4 until we parse the comments\n\n   if (is_info) return 1;\n\n   if (g->flags & 0x80)\n      stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);\n\n   return 1;\n}\n\nstatic int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)\n{\n   stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));\n   if (!g) return stbi__err(\"outofmem\", \"Out of memory\");\n   if (!stbi__gif_header(s, g, comp, 1)) {\n      STBI_FREE(g);\n      stbi__rewind( s );\n      return 0;\n   }\n   if (x) *x = g->w;\n   if (y) *y = g->h;\n   STBI_FREE(g);\n   return 1;\n}\n\nstatic void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)\n{\n   stbi_uc *p, *c;\n   int idx;\n\n   // recurse to decode the prefixes, since the linked-list is backwards,\n   // and working backwards through an interleaved image would be nasty\n   if (g->codes[code].prefix >= 0)\n      stbi__out_gif_code(g, g->codes[code].prefix);\n\n   if (g->cur_y >= g->max_y) return;\n\n   idx = g->cur_x + g->cur_y;\n   p = &g->out[idx];\n   g->history[idx / 4] = 1;\n\n   c = &g->color_table[g->codes[code].suffix * 4];\n   if (c[3] > 128) { // don't render transparent pixels;\n      p[0] = c[2];\n      p[1] = c[1];\n      p[2] = c[0];\n      p[3] = c[3];\n   }\n   g->cur_x += 4;\n\n   if (g->cur_x >= g->max_x) {\n      g->cur_x = g->start_x;\n      g->cur_y += g->step;\n\n      while (g->cur_y >= g->max_y && g->parse > 0) {\n         g->step = (1 << g->parse) * g->line_size;\n         g->cur_y = g->start_y + (g->step >> 1);\n         --g->parse;\n      }\n   }\n}\n\nstatic stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)\n{\n   stbi_uc lzw_cs;\n   stbi__int32 len, init_code;\n   stbi__uint32 first;\n   stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;\n   stbi__gif_lzw *p;\n\n   lzw_cs = stbi__get8(s);\n   if (lzw_cs > 12) return NULL;\n   clear = 1 << lzw_cs;\n   first = 1;\n   codesize = lzw_cs + 1;\n   codemask = (1 << codesize) - 1;\n   bits = 0;\n   valid_bits = 0;\n   for (init_code = 0; init_code < clear; init_code++) {\n      g->codes[init_code].prefix = -1;\n      g->codes[init_code].first = (stbi_uc) init_code;\n      g->codes[init_code].suffix = (stbi_uc) init_code;\n   }\n\n   // support no starting clear code\n   avail = clear+2;\n   oldcode = -1;\n\n   len = 0;\n   for(;;) {\n      if (valid_bits < codesize) {\n         if (len == 0) {\n            len = stbi__get8(s); // start new block\n            if (len == 0)\n               return g->out;\n         }\n         --len;\n         bits |= (stbi__int32) stbi__get8(s) << valid_bits;\n         valid_bits += 8;\n      } else {\n         stbi__int32 code = bits & codemask;\n         bits >>= codesize;\n         valid_bits -= codesize;\n         // @OPTIMIZE: is there some way we can accelerate the non-clear path?\n         if (code == clear) {  // clear code\n            codesize = lzw_cs + 1;\n            codemask = (1 << codesize) - 1;\n            avail = clear + 2;\n            oldcode = -1;\n            first = 0;\n         } else if (code == clear + 1) { // end of stream code\n            stbi__skip(s, len);\n            while ((len = stbi__get8(s)) > 0)\n               stbi__skip(s,len);\n            return g->out;\n         } else if (code <= avail) {\n            if (first) {\n               return stbi__errpuc(\"no clear code\", \"Corrupt GIF\");\n            }\n\n            if (oldcode >= 0) {\n               p = &g->codes[avail++];\n               if (avail > 8192) {\n                  return stbi__errpuc(\"too many codes\", \"Corrupt GIF\");\n               }\n\n               p->prefix = (stbi__int16) oldcode;\n               p->first = g->codes[oldcode].first;\n               p->suffix = (code == avail) ? p->first : g->codes[code].first;\n            } else if (code == avail)\n               return stbi__errpuc(\"illegal code in raster\", \"Corrupt GIF\");\n\n            stbi__out_gif_code(g, (stbi__uint16) code);\n\n            if ((avail & codemask) == 0 && avail <= 0x0FFF) {\n               codesize++;\n               codemask = (1 << codesize) - 1;\n            }\n\n            oldcode = code;\n         } else {\n            return stbi__errpuc(\"illegal code in raster\", \"Corrupt GIF\");\n         }\n      }\n   }\n}\n\n// this function is designed to support animated gifs, although stb_image doesn't support it\n// two back is the image from two frames ago, used for a very specific disposal format\nstatic stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp, stbi_uc *two_back)\n{\n   int dispose;\n   int first_frame;\n   int pi;\n   int pcount;\n   STBI_NOTUSED(req_comp);\n\n   // on first frame, any non-written pixels get the background colour (non-transparent)\n   first_frame = 0;\n   if (g->out == 0) {\n      if (!stbi__gif_header(s, g, comp,0)) return 0; // stbi__g_failure_reason set by stbi__gif_header\n      if (!stbi__mad3sizes_valid(4, g->w, g->h, 0))\n         return stbi__errpuc(\"too large\", \"GIF image is too large\");\n      pcount = g->w * g->h;\n      g->out = (stbi_uc *) stbi__malloc(4 * pcount);\n      g->background = (stbi_uc *) stbi__malloc(4 * pcount);\n      g->history = (stbi_uc *) stbi__malloc(pcount);\n      if (!g->out || !g->background || !g->history)\n         return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n      // image is treated as \"transparent\" at the start - ie, nothing overwrites the current background;\n      // background colour is only used for pixels that are not rendered first frame, after that \"background\"\n      // color refers to the color that was there the previous frame.\n      memset(g->out, 0x00, 4 * pcount);\n      memset(g->background, 0x00, 4 * pcount); // state of the background (starts transparent)\n      memset(g->history, 0x00, pcount);        // pixels that were affected previous frame\n      first_frame = 1;\n   } else {\n      // second frame - how do we dispose of the previous one?\n      dispose = (g->eflags & 0x1C) >> 2;\n      pcount = g->w * g->h;\n\n      if ((dispose == 3) && (two_back == 0)) {\n         dispose = 2; // if I don't have an image to revert back to, default to the old background\n      }\n\n      if (dispose == 3) { // use previous graphic\n         for (pi = 0; pi < pcount; ++pi) {\n            if (g->history[pi]) {\n               memcpy( &g->out[pi * 4], &two_back[pi * 4], 4 );\n            }\n         }\n      } else if (dispose == 2) {\n         // restore what was changed last frame to background before that frame;\n         for (pi = 0; pi < pcount; ++pi) {\n            if (g->history[pi]) {\n               memcpy( &g->out[pi * 4], &g->background[pi * 4], 4 );\n            }\n         }\n      } else {\n         // This is a non-disposal case eithe way, so just\n         // leave the pixels as is, and they will become the new background\n         // 1: do not dispose\n         // 0:  not specified.\n      }\n\n      // background is what out is after the undoing of the previou frame;\n      memcpy( g->background, g->out, 4 * g->w * g->h );\n   }\n\n   // clear my history;\n   memset( g->history, 0x00, g->w * g->h );        // pixels that were affected previous frame\n\n   for (;;) {\n      int tag = stbi__get8(s);\n      switch (tag) {\n         case 0x2C: /* Image Descriptor */\n         {\n            stbi__int32 x, y, w, h;\n            stbi_uc *o;\n\n            x = stbi__get16le(s);\n            y = stbi__get16le(s);\n            w = stbi__get16le(s);\n            h = stbi__get16le(s);\n            if (((x + w) > (g->w)) || ((y + h) > (g->h)))\n               return stbi__errpuc(\"bad Image Descriptor\", \"Corrupt GIF\");\n\n            g->line_size = g->w * 4;\n            g->start_x = x * 4;\n            g->start_y = y * g->line_size;\n            g->max_x   = g->start_x + w * 4;\n            g->max_y   = g->start_y + h * g->line_size;\n            g->cur_x   = g->start_x;\n            g->cur_y   = g->start_y;\n\n            // if the width of the specified rectangle is 0, that means\n            // we may not see *any* pixels or the image is malformed;\n            // to make sure this is caught, move the current y down to\n            // max_y (which is what out_gif_code checks).\n            if (w == 0)\n               g->cur_y = g->max_y;\n\n            g->lflags = stbi__get8(s);\n\n            if (g->lflags & 0x40) {\n               g->step = 8 * g->line_size; // first interlaced spacing\n               g->parse = 3;\n            } else {\n               g->step = g->line_size;\n               g->parse = 0;\n            }\n\n            if (g->lflags & 0x80) {\n               stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);\n               g->color_table = (stbi_uc *) g->lpal;\n            } else if (g->flags & 0x80) {\n               g->color_table = (stbi_uc *) g->pal;\n            } else\n               return stbi__errpuc(\"missing color table\", \"Corrupt GIF\");\n\n            o = stbi__process_gif_raster(s, g);\n            if (!o) return NULL;\n\n            // if this was the first frame,\n            pcount = g->w * g->h;\n            if (first_frame && (g->bgindex > 0)) {\n               // if first frame, any pixel not drawn to gets the background color\n               for (pi = 0; pi < pcount; ++pi) {\n                  if (g->history[pi] == 0) {\n                     g->pal[g->bgindex][3] = 255; // just in case it was made transparent, undo that; It will be reset next frame if need be;\n                     memcpy( &g->out[pi * 4], &g->pal[g->bgindex], 4 );\n                  }\n               }\n            }\n\n            return o;\n         }\n\n         case 0x21: // Comment Extension.\n         {\n            int len;\n            int ext = stbi__get8(s);\n            if (ext == 0xF9) { // Graphic Control Extension.\n               len = stbi__get8(s);\n               if (len == 4) {\n                  g->eflags = stbi__get8(s);\n                  g->delay = 10 * stbi__get16le(s); // delay - 1/100th of a second, saving as 1/1000ths.\n\n                  // unset old transparent\n                  if (g->transparent >= 0) {\n                     g->pal[g->transparent][3] = 255;\n                  }\n                  if (g->eflags & 0x01) {\n                     g->transparent = stbi__get8(s);\n                     if (g->transparent >= 0) {\n                        g->pal[g->transparent][3] = 0;\n                     }\n                  } else {\n                     // don't need transparent\n                     stbi__skip(s, 1);\n                     g->transparent = -1;\n                  }\n               } else {\n                  stbi__skip(s, len);\n                  break;\n               }\n            }\n            while ((len = stbi__get8(s)) != 0) {\n               stbi__skip(s, len);\n            }\n            break;\n         }\n\n         case 0x3B: // gif stream termination code\n            return (stbi_uc *) s; // using '1' causes warning on some compilers\n\n         default:\n            return stbi__errpuc(\"unknown code\", \"Corrupt GIF\");\n      }\n   }\n}\n\nstatic void *stbi__load_gif_main_outofmem(stbi__gif *g, stbi_uc *out, int **delays)\n{\n   STBI_FREE(g->out);\n   STBI_FREE(g->history);\n   STBI_FREE(g->background);\n\n   if (out) STBI_FREE(out);\n   if (delays && *delays) STBI_FREE(*delays);\n   return stbi__errpuc(\"outofmem\", \"Out of memory\");\n}\n\nstatic void *stbi__load_gif_main(stbi__context *s, int **delays, int *x, int *y, int *z, int *comp, int req_comp)\n{\n   if (stbi__gif_test(s)) {\n      int layers = 0;\n      stbi_uc *u = 0;\n      stbi_uc *out = 0;\n      stbi_uc *two_back = 0;\n      stbi__gif g;\n      int stride;\n      int out_size = 0;\n      int delays_size = 0;\n\n      STBI_NOTUSED(out_size);\n      STBI_NOTUSED(delays_size);\n\n      memset(&g, 0, sizeof(g));\n      if (delays) {\n         *delays = 0;\n      }\n\n      do {\n         u = stbi__gif_load_next(s, &g, comp, req_comp, two_back);\n         if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker\n\n         if (u) {\n            *x = g.w;\n            *y = g.h;\n            ++layers;\n            stride = g.w * g.h * 4;\n\n            if (out) {\n               void *tmp = (stbi_uc*) STBI_REALLOC_SIZED( out, out_size, layers * stride );\n               if (!tmp)\n                  return stbi__load_gif_main_outofmem(&g, out, delays);\n               else {\n                   out = (stbi_uc*) tmp;\n                   out_size = layers * stride;\n               }\n\n               if (delays) {\n                  int *new_delays = (int*) STBI_REALLOC_SIZED( *delays, delays_size, sizeof(int) * layers );\n                  if (!new_delays)\n                     return stbi__load_gif_main_outofmem(&g, out, delays);\n                  *delays = new_delays;\n                  delays_size = layers * sizeof(int);\n               }\n            } else {\n               out = (stbi_uc*)stbi__malloc( layers * stride );\n               if (!out)\n                  return stbi__load_gif_main_outofmem(&g, out, delays);\n               out_size = layers * stride;\n               if (delays) {\n                  *delays = (int*) stbi__malloc( layers * sizeof(int) );\n                  if (!*delays)\n                     return stbi__load_gif_main_outofmem(&g, out, delays);\n                  delays_size = layers * sizeof(int);\n               }\n            }\n            memcpy( out + ((layers - 1) * stride), u, stride );\n            if (layers >= 2) {\n               two_back = out - 2 * stride;\n            }\n\n            if (delays) {\n               (*delays)[layers - 1U] = g.delay;\n            }\n         }\n      } while (u != 0);\n\n      // free temp buffer;\n      STBI_FREE(g.out);\n      STBI_FREE(g.history);\n      STBI_FREE(g.background);\n\n      // do the final conversion after loading everything;\n      if (req_comp && req_comp != 4)\n         out = stbi__convert_format(out, 4, req_comp, layers * g.w, g.h);\n\n      *z = layers;\n      return out;\n   } else {\n      return stbi__errpuc(\"not GIF\", \"Image was not as a gif type.\");\n   }\n}\n\nstatic void *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *u = 0;\n   stbi__gif g;\n   memset(&g, 0, sizeof(g));\n   STBI_NOTUSED(ri);\n\n   u = stbi__gif_load_next(s, &g, comp, req_comp, 0);\n   if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker\n   if (u) {\n      *x = g.w;\n      *y = g.h;\n\n      // moved conversion to after successful load so that the same\n      // can be done for multiple frames.\n      if (req_comp && req_comp != 4)\n         u = stbi__convert_format(u, 4, req_comp, g.w, g.h);\n   } else if (g.out) {\n      // if there was an error and we allocated an image buffer, free it!\n      STBI_FREE(g.out);\n   }\n\n   // free buffers needed for multiple frame loading;\n   STBI_FREE(g.history);\n   STBI_FREE(g.background);\n\n   return u;\n}\n\nstatic int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   return stbi__gif_info_raw(s,x,y,comp);\n}\n#endif\n\n// *************************************************************************************************\n// Radiance RGBE HDR loader\n// originally by Nicolas Schulz\n#ifndef STBI_NO_HDR\nstatic int stbi__hdr_test_core(stbi__context *s, const char *signature)\n{\n   int i;\n   for (i=0; signature[i]; ++i)\n      if (stbi__get8(s) != signature[i])\n          return 0;\n   stbi__rewind(s);\n   return 1;\n}\n\nstatic int stbi__hdr_test(stbi__context* s)\n{\n   int r = stbi__hdr_test_core(s, \"#?RADIANCE\\n\");\n   stbi__rewind(s);\n   if(!r) {\n       r = stbi__hdr_test_core(s, \"#?RGBE\\n\");\n       stbi__rewind(s);\n   }\n   return r;\n}\n\n#define STBI__HDR_BUFLEN  1024\nstatic char *stbi__hdr_gettoken(stbi__context *z, char *buffer)\n{\n   int len=0;\n   char c = '\\0';\n\n   c = (char) stbi__get8(z);\n\n   while (!stbi__at_eof(z) && c != '\\n') {\n      buffer[len++] = c;\n      if (len == STBI__HDR_BUFLEN-1) {\n         // flush to end of line\n         while (!stbi__at_eof(z) && stbi__get8(z) != '\\n')\n            ;\n         break;\n      }\n      c = (char) stbi__get8(z);\n   }\n\n   buffer[len] = 0;\n   return buffer;\n}\n\nstatic void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)\n{\n   if ( input[3] != 0 ) {\n      float f1;\n      // Exponent\n      f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));\n      if (req_comp <= 2)\n         output[0] = (input[0] + input[1] + input[2]) * f1 / 3;\n      else {\n         output[0] = input[0] * f1;\n         output[1] = input[1] * f1;\n         output[2] = input[2] * f1;\n      }\n      if (req_comp == 2) output[1] = 1;\n      if (req_comp == 4) output[3] = 1;\n   } else {\n      switch (req_comp) {\n         case 4: output[3] = 1; /* fallthrough */\n         case 3: output[0] = output[1] = output[2] = 0;\n                 break;\n         case 2: output[1] = 1; /* fallthrough */\n         case 1: output[0] = 0;\n                 break;\n      }\n   }\n}\n\nstatic float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   char buffer[STBI__HDR_BUFLEN];\n   char *token;\n   int valid = 0;\n   int width, height;\n   stbi_uc *scanline;\n   float *hdr_data;\n   int len;\n   unsigned char count, value;\n   int i, j, k, c1,c2, z;\n   const char *headerToken;\n   STBI_NOTUSED(ri);\n\n   // Check identifier\n   headerToken = stbi__hdr_gettoken(s,buffer);\n   if (strcmp(headerToken, \"#?RADIANCE\") != 0 && strcmp(headerToken, \"#?RGBE\") != 0)\n      return stbi__errpf(\"not HDR\", \"Corrupt HDR image\");\n\n   // Parse header\n   for(;;) {\n      token = stbi__hdr_gettoken(s,buffer);\n      if (token[0] == 0) break;\n      if (strcmp(token, \"FORMAT=32-bit_rle_rgbe\") == 0) valid = 1;\n   }\n\n   if (!valid)    return stbi__errpf(\"unsupported format\", \"Unsupported HDR format\");\n\n   // Parse width and height\n   // can't use sscanf() if we're not using stdio!\n   token = stbi__hdr_gettoken(s,buffer);\n   if (strncmp(token, \"-Y \", 3))  return stbi__errpf(\"unsupported data layout\", \"Unsupported HDR format\");\n   token += 3;\n   height = (int) strtol(token, &token, 10);\n   while (*token == ' ') ++token;\n   if (strncmp(token, \"+X \", 3))  return stbi__errpf(\"unsupported data layout\", \"Unsupported HDR format\");\n   token += 3;\n   width = (int) strtol(token, NULL, 10);\n\n   if (height > STBI_MAX_DIMENSIONS) return stbi__errpf(\"too large\",\"Very large image (corrupt?)\");\n   if (width > STBI_MAX_DIMENSIONS) return stbi__errpf(\"too large\",\"Very large image (corrupt?)\");\n\n   *x = width;\n   *y = height;\n\n   if (comp) *comp = 3;\n   if (req_comp == 0) req_comp = 3;\n\n   if (!stbi__mad4sizes_valid(width, height, req_comp, sizeof(float), 0))\n      return stbi__errpf(\"too large\", \"HDR image is too large\");\n\n   // Read data\n   hdr_data = (float *) stbi__malloc_mad4(width, height, req_comp, sizeof(float), 0);\n   if (!hdr_data)\n      return stbi__errpf(\"outofmem\", \"Out of memory\");\n\n   // Load image data\n   // image data is stored as some number of sca\n   if ( width < 8 || width >= 32768) {\n      // Read flat data\n      for (j=0; j < height; ++j) {\n         for (i=0; i < width; ++i) {\n            stbi_uc rgbe[4];\n           main_decode_loop:\n            stbi__getn(s, rgbe, 4);\n            stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);\n         }\n      }\n   } else {\n      // Read RLE-encoded data\n      scanline = NULL;\n\n      for (j = 0; j < height; ++j) {\n         c1 = stbi__get8(s);\n         c2 = stbi__get8(s);\n         len = stbi__get8(s);\n         if (c1 != 2 || c2 != 2 || (len & 0x80)) {\n            // not run-length encoded, so we have to actually use THIS data as a decoded\n            // pixel (note this can't be a valid pixel--one of RGB must be >= 128)\n            stbi_uc rgbe[4];\n            rgbe[0] = (stbi_uc) c1;\n            rgbe[1] = (stbi_uc) c2;\n            rgbe[2] = (stbi_uc) len;\n            rgbe[3] = (stbi_uc) stbi__get8(s);\n            stbi__hdr_convert(hdr_data, rgbe, req_comp);\n            i = 1;\n            j = 0;\n            STBI_FREE(scanline);\n            goto main_decode_loop; // yes, this makes no sense\n         }\n         len <<= 8;\n         len |= stbi__get8(s);\n         if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"invalid decoded scanline length\", \"corrupt HDR\"); }\n         if (scanline == NULL) {\n            scanline = (stbi_uc *) stbi__malloc_mad2(width, 4, 0);\n            if (!scanline) {\n               STBI_FREE(hdr_data);\n               return stbi__errpf(\"outofmem\", \"Out of memory\");\n            }\n         }\n\n         for (k = 0; k < 4; ++k) {\n            int nleft;\n            i = 0;\n            while ((nleft = width - i) > 0) {\n               count = stbi__get8(s);\n               if (count > 128) {\n                  // Run\n                  value = stbi__get8(s);\n                  count -= 128;\n                  if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"corrupt\", \"bad RLE data in HDR\"); }\n                  for (z = 0; z < count; ++z)\n                     scanline[i++ * 4 + k] = value;\n               } else {\n                  // Dump\n                  if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"corrupt\", \"bad RLE data in HDR\"); }\n                  for (z = 0; z < count; ++z)\n                     scanline[i++ * 4 + k] = stbi__get8(s);\n               }\n            }\n         }\n         for (i=0; i < width; ++i)\n            stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);\n      }\n      if (scanline)\n         STBI_FREE(scanline);\n   }\n\n   return hdr_data;\n}\n\nstatic int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   char buffer[STBI__HDR_BUFLEN];\n   char *token;\n   int valid = 0;\n   int dummy;\n\n   if (!x) x = &dummy;\n   if (!y) y = &dummy;\n   if (!comp) comp = &dummy;\n\n   if (stbi__hdr_test(s) == 0) {\n       stbi__rewind( s );\n       return 0;\n   }\n\n   for(;;) {\n      token = stbi__hdr_gettoken(s,buffer);\n      if (token[0] == 0) break;\n      if (strcmp(token, \"FORMAT=32-bit_rle_rgbe\") == 0) valid = 1;\n   }\n\n   if (!valid) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token = stbi__hdr_gettoken(s,buffer);\n   if (strncmp(token, \"-Y \", 3)) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token += 3;\n   *y = (int) strtol(token, &token, 10);\n   while (*token == ' ') ++token;\n   if (strncmp(token, \"+X \", 3)) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token += 3;\n   *x = (int) strtol(token, NULL, 10);\n   *comp = 3;\n   return 1;\n}\n#endif // STBI_NO_HDR\n\n#ifndef STBI_NO_BMP\nstatic int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   void *p;\n   stbi__bmp_data info;\n\n   info.all_a = 255;\n   p = stbi__bmp_parse_header(s, &info);\n   if (p == NULL) {\n      stbi__rewind( s );\n      return 0;\n   }\n   if (x) *x = s->img_x;\n   if (y) *y = s->img_y;\n   if (comp) {\n      if (info.bpp == 24 && info.ma == 0xff000000)\n         *comp = 3;\n      else\n         *comp = info.ma ? 4 : 3;\n   }\n   return 1;\n}\n#endif\n\n#ifndef STBI_NO_PSD\nstatic int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int channelCount, dummy, depth;\n   if (!x) x = &dummy;\n   if (!y) y = &dummy;\n   if (!comp) comp = &dummy;\n   if (stbi__get32be(s) != 0x38425053) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 1) {\n       stbi__rewind( s );\n       return 0;\n   }\n   stbi__skip(s, 6);\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   *y = stbi__get32be(s);\n   *x = stbi__get32be(s);\n   depth = stbi__get16be(s);\n   if (depth != 8 && depth != 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 3) {\n       stbi__rewind( s );\n       return 0;\n   }\n   *comp = 4;\n   return 1;\n}\n\nstatic int stbi__psd_is16(stbi__context *s)\n{\n   int channelCount, depth;\n   if (stbi__get32be(s) != 0x38425053) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 1) {\n       stbi__rewind( s );\n       return 0;\n   }\n   stbi__skip(s, 6);\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   STBI_NOTUSED(stbi__get32be(s));\n   STBI_NOTUSED(stbi__get32be(s));\n   depth = stbi__get16be(s);\n   if (depth != 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   return 1;\n}\n#endif\n\n#ifndef STBI_NO_PIC\nstatic int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int act_comp=0,num_packets=0,chained,dummy;\n   stbi__pic_packet packets[10];\n\n   if (!x) x = &dummy;\n   if (!y) y = &dummy;\n   if (!comp) comp = &dummy;\n\n   if (!stbi__pic_is4(s,\"\\x53\\x80\\xF6\\x34\")) {\n      stbi__rewind(s);\n      return 0;\n   }\n\n   stbi__skip(s, 88);\n\n   *x = stbi__get16be(s);\n   *y = stbi__get16be(s);\n   if (stbi__at_eof(s)) {\n      stbi__rewind( s);\n      return 0;\n   }\n   if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {\n      stbi__rewind( s );\n      return 0;\n   }\n\n   stbi__skip(s, 8);\n\n   do {\n      stbi__pic_packet *packet;\n\n      if (num_packets==sizeof(packets)/sizeof(packets[0]))\n         return 0;\n\n      packet = &packets[num_packets++];\n      chained = stbi__get8(s);\n      packet->size    = stbi__get8(s);\n      packet->type    = stbi__get8(s);\n      packet->channel = stbi__get8(s);\n      act_comp |= packet->channel;\n\n      if (stbi__at_eof(s)) {\n          stbi__rewind( s );\n          return 0;\n      }\n      if (packet->size != 8) {\n          stbi__rewind( s );\n          return 0;\n      }\n   } while (chained);\n\n   *comp = (act_comp & 0x10 ? 4 : 3);\n\n   return 1;\n}\n#endif\n\n// *************************************************************************************************\n// Portable Gray Map and Portable Pixel Map loader\n// by Ken Miller\n//\n// PGM: http://netpbm.sourceforge.net/doc/pgm.html\n// PPM: http://netpbm.sourceforge.net/doc/ppm.html\n//\n// Known limitations:\n//    Does not support comments in the header section\n//    Does not support ASCII image data (formats P2 and P3)\n\n#ifndef STBI_NO_PNM\n\nstatic int      stbi__pnm_test(stbi__context *s)\n{\n   char p, t;\n   p = (char) stbi__get8(s);\n   t = (char) stbi__get8(s);\n   if (p != 'P' || (t != '5' && t != '6')) {\n       stbi__rewind( s );\n       return 0;\n   }\n   return 1;\n}\n\nstatic void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)\n{\n   stbi_uc *out;\n   STBI_NOTUSED(ri);\n\n   ri->bits_per_channel = stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n);\n   if (ri->bits_per_channel == 0)\n      return 0;\n\n   if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n   if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__errpuc(\"too large\",\"Very large image (corrupt?)\");\n\n   *x = s->img_x;\n   *y = s->img_y;\n   if (comp) *comp = s->img_n;\n\n   if (!stbi__mad4sizes_valid(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0))\n      return stbi__errpuc(\"too large\", \"PNM too large\");\n\n   out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0);\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) {\n      STBI_FREE(out);\n      return stbi__errpuc(\"bad PNM\", \"PNM file truncated\");\n   }\n\n   if (req_comp && req_comp != s->img_n) {\n      if (ri->bits_per_channel == 16) {\n         out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y);\n      } else {\n         out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);\n      }\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n   return out;\n}\n\nstatic int      stbi__pnm_isspace(char c)\n{\n   return c == ' ' || c == '\\t' || c == '\\n' || c == '\\v' || c == '\\f' || c == '\\r';\n}\n\nstatic void     stbi__pnm_skip_whitespace(stbi__context *s, char *c)\n{\n   for (;;) {\n      while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))\n         *c = (char) stbi__get8(s);\n\n      if (stbi__at_eof(s) || *c != '#')\n         break;\n\n      while (!stbi__at_eof(s) && *c != '\\n' && *c != '\\r' )\n         *c = (char) stbi__get8(s);\n   }\n}\n\nstatic int      stbi__pnm_isdigit(char c)\n{\n   return c >= '0' && c <= '9';\n}\n\nstatic int      stbi__pnm_getinteger(stbi__context *s, char *c)\n{\n   int value = 0;\n\n   while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {\n      value = value*10 + (*c - '0');\n      *c = (char) stbi__get8(s);\n      if((value > 214748364) || (value == 214748364 && *c > '7'))\n          return stbi__err(\"integer parse overflow\", \"Parsing an integer in the PPM header overflowed a 32-bit int\");\n   }\n\n   return value;\n}\n\nstatic int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int maxv, dummy;\n   char c, p, t;\n\n   if (!x) x = &dummy;\n   if (!y) y = &dummy;\n   if (!comp) comp = &dummy;\n\n   stbi__rewind(s);\n\n   // Get identifier\n   p = (char) stbi__get8(s);\n   t = (char) stbi__get8(s);\n   if (p != 'P' || (t != '5' && t != '6')) {\n       stbi__rewind(s);\n       return 0;\n   }\n\n   *comp = (t == '6') ? 3 : 1;  // '5' is 1-component .pgm; '6' is 3-component .ppm\n\n   c = (char) stbi__get8(s);\n   stbi__pnm_skip_whitespace(s, &c);\n\n   *x = stbi__pnm_getinteger(s, &c); // read width\n   if(*x == 0)\n       return stbi__err(\"invalid width\", \"PPM image header had zero or overflowing width\");\n   stbi__pnm_skip_whitespace(s, &c);\n\n   *y = stbi__pnm_getinteger(s, &c); // read height\n   if (*y == 0)\n       return stbi__err(\"invalid width\", \"PPM image header had zero or overflowing width\");\n   stbi__pnm_skip_whitespace(s, &c);\n\n   maxv = stbi__pnm_getinteger(s, &c);  // read max value\n   if (maxv > 65535)\n      return stbi__err(\"max value > 65535\", \"PPM image supports only 8-bit and 16-bit images\");\n   else if (maxv > 255)\n      return 16;\n   else\n      return 8;\n}\n\nstatic int stbi__pnm_is16(stbi__context *s)\n{\n   if (stbi__pnm_info(s, NULL, NULL, NULL) == 16)\n\t   return 1;\n   return 0;\n}\n#endif\n\nstatic int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)\n{\n   #ifndef STBI_NO_JPEG\n   if (stbi__jpeg_info(s, x, y, comp)) return 1;\n   #endif\n\n   #ifndef STBI_NO_PNG\n   if (stbi__png_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_GIF\n   if (stbi__gif_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_BMP\n   if (stbi__bmp_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PIC\n   if (stbi__pic_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_info(s, x, y, comp))  return 1;\n   #endif\n\n   // test tga last because it's a crappy test!\n   #ifndef STBI_NO_TGA\n   if (stbi__tga_info(s, x, y, comp))\n       return 1;\n   #endif\n   return stbi__err(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nstatic int stbi__is_16_main(stbi__context *s)\n{\n   #ifndef STBI_NO_PNG\n   if (stbi__png_is16(s))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_is16(s))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_is16(s))  return 1;\n   #endif\n   return 0;\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)\n{\n    FILE *f = stbi__fopen(filename, \"rb\");\n    int result;\n    if (!f) return stbi__err(\"can't fopen\", \"Unable to open file\");\n    result = stbi_info_from_file(f, x, y, comp);\n    fclose(f);\n    return result;\n}\n\nSTBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)\n{\n   int r;\n   stbi__context s;\n   long pos = ftell(f);\n   stbi__start_file(&s, f);\n   r = stbi__info_main(&s,x,y,comp);\n   fseek(f,pos,SEEK_SET);\n   return r;\n}\n\nSTBIDEF int stbi_is_16_bit(char const *filename)\n{\n    FILE *f = stbi__fopen(filename, \"rb\");\n    int result;\n    if (!f) return stbi__err(\"can't fopen\", \"Unable to open file\");\n    result = stbi_is_16_bit_from_file(f);\n    fclose(f);\n    return result;\n}\n\nSTBIDEF int stbi_is_16_bit_from_file(FILE *f)\n{\n   int r;\n   stbi__context s;\n   long pos = ftell(f);\n   stbi__start_file(&s, f);\n   r = stbi__is_16_main(&s);\n   fseek(f,pos,SEEK_SET);\n   return r;\n}\n#endif // !STBI_NO_STDIO\n\nSTBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__info_main(&s,x,y,comp);\n}\n\nSTBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);\n   return stbi__info_main(&s,x,y,comp);\n}\n\nSTBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__is_16_main(&s);\n}\n\nSTBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);\n   return stbi__is_16_main(&s);\n}\n\n#endif // STB_IMAGE_IMPLEMENTATION\n\n/*\n   revision history:\n      2.20  (2019-02-07) support utf8 filenames in Windows; fix warnings and platform ifdefs\n      2.19  (2018-02-11) fix warning\n      2.18  (2018-01-30) fix warnings\n      2.17  (2018-01-29) change sbti__shiftsigned to avoid clang -O2 bug\n                         1-bit BMP\n                         *_is_16_bit api\n                         avoid warnings\n      2.16  (2017-07-23) all functions have 16-bit variants;\n                         STBI_NO_STDIO works again;\n                         compilation fixes;\n                         fix rounding in unpremultiply;\n                         optimize vertical flip;\n                         disable raw_len validation;\n                         documentation fixes\n      2.15  (2017-03-18) fix png-1,2,4 bug; now all Imagenet JPGs decode;\n                         warning fixes; disable run-time SSE detection on gcc;\n                         uniform handling of optional \"return\" values;\n                         thread-safe initialization of zlib tables\n      2.14  (2017-03-03) remove deprecated STBI_JPEG_OLD; fixes for Imagenet JPGs\n      2.13  (2016-11-29) add 16-bit API, only supported for PNG right now\n      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes\n      2.11  (2016-04-02) allocate large structures on the stack\n                         remove white matting for transparent PSD\n                         fix reported channel count for PNG & BMP\n                         re-enable SSE2 in non-gcc 64-bit\n                         support RGB-formatted JPEG\n                         read 16-bit PNGs (only as 8-bit)\n      2.10  (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED\n      2.09  (2016-01-16) allow comments in PNM files\n                         16-bit-per-pixel TGA (not bit-per-component)\n                         info() for TGA could break due to .hdr handling\n                         info() for BMP to shares code instead of sloppy parse\n                         can use STBI_REALLOC_SIZED if allocator doesn't support realloc\n                         code cleanup\n      2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA\n      2.07  (2015-09-13) fix compiler warnings\n                         partial animated GIF support\n                         limited 16-bpc PSD support\n                         #ifdef unused functions\n                         bug with < 92 byte PIC,PNM,HDR,TGA\n      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value\n      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning\n      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit\n      2.03  (2015-04-12) extra corruption checking (mmozeiko)\n                         stbi_set_flip_vertically_on_load (nguillemot)\n                         fix NEON support; fix mingw support\n      2.02  (2015-01-19) fix incorrect assert, fix warning\n      2.01  (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2\n      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG\n      2.00  (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)\n                         progressive JPEG (stb)\n                         PGM/PPM support (Ken Miller)\n                         STBI_MALLOC,STBI_REALLOC,STBI_FREE\n                         GIF bugfix -- seemingly never worked\n                         STBI_NO_*, STBI_ONLY_*\n      1.48  (2014-12-14) fix incorrectly-named assert()\n      1.47  (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)\n                         optimize PNG (ryg)\n                         fix bug in interlaced PNG with user-specified channel count (stb)\n      1.46  (2014-08-26)\n              fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG\n      1.45  (2014-08-16)\n              fix MSVC-ARM internal compiler error by wrapping malloc\n      1.44  (2014-08-07)\n              various warning fixes from Ronny Chevalier\n      1.43  (2014-07-15)\n              fix MSVC-only compiler problem in code changed in 1.42\n      1.42  (2014-07-09)\n              don't define _CRT_SECURE_NO_WARNINGS (affects user code)\n              fixes to stbi__cleanup_jpeg path\n              added STBI_ASSERT to avoid requiring assert.h\n      1.41  (2014-06-25)\n              fix search&replace from 1.36 that messed up comments/error messages\n      1.40  (2014-06-22)\n              fix gcc struct-initialization warning\n      1.39  (2014-06-15)\n              fix to TGA optimization when req_comp != number of components in TGA;\n              fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)\n              add support for BMP version 5 (more ignored fields)\n      1.38  (2014-06-06)\n              suppress MSVC warnings on integer casts truncating values\n              fix accidental rename of 'skip' field of I/O\n      1.37  (2014-06-04)\n              remove duplicate typedef\n      1.36  (2014-06-03)\n              convert to header file single-file library\n              if de-iphone isn't set, load iphone images color-swapped instead of returning NULL\n      1.35  (2014-05-27)\n              various warnings\n              fix broken STBI_SIMD path\n              fix bug where stbi_load_from_file no longer left file pointer in correct place\n              fix broken non-easy path for 32-bit BMP (possibly never used)\n              TGA optimization by Arseny Kapoulkine\n      1.34  (unknown)\n              use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case\n      1.33  (2011-07-14)\n              make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements\n      1.32  (2011-07-13)\n              support for \"info\" function for all supported filetypes (SpartanJ)\n      1.31  (2011-06-20)\n              a few more leak fixes, bug in PNG handling (SpartanJ)\n      1.30  (2011-06-11)\n              added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)\n              removed deprecated format-specific test/load functions\n              removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway\n              error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)\n              fix inefficiency in decoding 32-bit BMP (David Woo)\n      1.29  (2010-08-16)\n              various warning fixes from Aurelien Pocheville\n      1.28  (2010-08-01)\n              fix bug in GIF palette transparency (SpartanJ)\n      1.27  (2010-08-01)\n              cast-to-stbi_uc to fix warnings\n      1.26  (2010-07-24)\n              fix bug in file buffering for PNG reported by SpartanJ\n      1.25  (2010-07-17)\n              refix trans_data warning (Won Chun)\n      1.24  (2010-07-12)\n              perf improvements reading from files on platforms with lock-heavy fgetc()\n              minor perf improvements for jpeg\n              deprecated type-specific functions so we'll get feedback if they're needed\n              attempt to fix trans_data warning (Won Chun)\n      1.23    fixed bug in iPhone support\n      1.22  (2010-07-10)\n              removed image *writing* support\n              stbi_info support from Jetro Lauha\n              GIF support from Jean-Marc Lienher\n              iPhone PNG-extensions from James Brown\n              warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)\n      1.21    fix use of 'stbi_uc' in header (reported by jon blow)\n      1.20    added support for Softimage PIC, by Tom Seddon\n      1.19    bug in interlaced PNG corruption check (found by ryg)\n      1.18  (2008-08-02)\n              fix a threading bug (local mutable static)\n      1.17    support interlaced PNG\n      1.16    major bugfix - stbi__convert_format converted one too many pixels\n      1.15    initialize some fields for thread safety\n      1.14    fix threadsafe conversion bug\n              header-file-only version (#define STBI_HEADER_FILE_ONLY before including)\n      1.13    threadsafe\n      1.12    const qualifiers in the API\n      1.11    Support installable IDCT, colorspace conversion routines\n      1.10    Fixes for 64-bit (don't use \"unsigned long\")\n              optimized upsampling by Fabian \"ryg\" Giesen\n      1.09    Fix format-conversion for PSD code (bad global variables!)\n      1.08    Thatcher Ulrich's PSD code integrated by Nicolas Schulz\n      1.07    attempt to fix C++ warning/errors again\n      1.06    attempt to fix C++ warning/errors again\n      1.05    fix TGA loading to return correct *comp and use good luminance calc\n      1.04    default float alpha is 1, not 255; use 'void *' for stbi_image_free\n      1.03    bugfixes to STBI_NO_STDIO, STBI_NO_HDR\n      1.02    support for (subset of) HDR files, float interface for preferred access to them\n      1.01    fix bug: possible bug in handling right-side up bmps... not sure\n              fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all\n      1.00    interface to zlib that skips zlib header\n      0.99    correct handling of alpha in palette\n      0.98    TGA loader by lonesock; dynamically add loaders (untested)\n      0.97    jpeg errors on too large a file; also catch another malloc failure\n      0.96    fix detection of invalid v value - particleman@mollyrocket forum\n      0.95    during header scan, seek to markers in case of padding\n      0.94    STBI_NO_STDIO to disable stdio usage; rename all #defines the same\n      0.93    handle jpegtran output; verbose errors\n      0.92    read 4,8,16,24,32-bit BMP files of several formats\n      0.91    output 24-bit Windows 3.0 BMP files\n      0.90    fix a few more warnings; bump version number to approach 1.0\n      0.61    bugfixes due to Marc LeBlanc, Christopher Lloyd\n      0.60    fix compiling as c++\n      0.59    fix warnings: merge Dave Moore's -Wall fixes\n      0.58    fix bug: zlib uncompressed mode len/nlen was wrong endian\n      0.57    fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available\n      0.56    fix bug: zlib uncompressed mode len vs. nlen\n      0.55    fix bug: restart_interval not initialized to 0\n      0.54    allow NULL for 'int *comp'\n      0.53    fix bug in png 3->4; speedup png decoding\n      0.52    png handles req_comp=3,4 directly; minor cleanup; jpeg comments\n      0.51    obey req_comp requests, 1-component jpegs return as 1-component,\n              on 'test' only check type, not whether we support this variant\n      0.50  (2006-11-19)\n              first released version\n*/\n\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "demo/common/node_editor.c",
    "content": "/* nuklear - v1.00 - public domain */\n/* This is a simple node editor just to show a simple implementation and that\n * it is possible to achieve it with this library. While all nodes inside this\n * example use a simple color modifier as content you could change them\n * to have your custom content depending on the node time.\n * Biggest difference to most usual implementation is that this example does\n * not have connectors on the right position of the property that it links.\n * This is mainly done out of laziness and could be implemented as well but\n * requires calculating the position of all rows and add connectors.\n * In addition adding and removing nodes is quite limited at the\n * moment since it is based on a simple fixed array. If this is to be converted\n * into something more serious it is probably best to extend it.*/\nstruct node {\n    int ID;\n    char name[32];\n    struct nk_rect bounds;\n    float value;\n    struct nk_color color;\n    int input_count;\n    int output_count;\n    struct node *next;\n    struct node *prev;\n};\n\nstruct node_link {\n    int input_id;\n    int input_slot;\n    int output_id;\n    int output_slot;\n    struct nk_vec2 in;\n    struct nk_vec2 out;\n};\n\nstruct node_linking {\n    int active;\n    struct node *node;\n    int input_id;\n    int input_slot;\n};\n\nstruct node_editor {\n    int initialized;\n    struct node node_buf[32];\n    struct node_link links[64];\n    struct node *begin;\n    struct node *end;\n    int node_count;\n    int link_count;\n    struct nk_rect bounds;\n    struct node *selected;\n    int show_grid;\n    struct nk_vec2 scrolling;\n    struct node_linking linking;\n};\nstatic struct node_editor nodeEditor;\n\nstatic void\nnode_editor_push(struct node_editor *editor, struct node *node)\n{\n    if (!editor->begin) {\n        node->next = NULL;\n        node->prev = NULL;\n        editor->begin = node;\n        editor->end = node;\n    } else {\n        node->prev = editor->end;\n        if (editor->end)\n            editor->end->next = node;\n        node->next = NULL;\n        editor->end = node;\n    }\n}\n\nstatic void\nnode_editor_pop(struct node_editor *editor, struct node *node)\n{\n    if (node->next)\n        node->next->prev = node->prev;\n    if (node->prev)\n        node->prev->next = node->next;\n    if (editor->end == node)\n        editor->end = node->prev;\n    if (editor->begin == node)\n        editor->begin = node->next;\n    node->next = NULL;\n    node->prev = NULL;\n}\n\nstatic struct node*\nnode_editor_find(struct node_editor *editor, int ID)\n{\n    struct node *iter = editor->begin;\n    while (iter) {\n        if (iter->ID == ID)\n            return iter;\n        iter = iter->next;\n    }\n    return NULL;\n}\n\nstatic void\nnode_editor_add(struct node_editor *editor, const char *name, struct nk_rect bounds,\n    struct nk_color col, int in_count, int out_count)\n{\n    static int IDs = 0;\n    struct node *node;\n    NK_ASSERT((nk_size)editor->node_count < NK_LEN(editor->node_buf));\n    node = &editor->node_buf[editor->node_count++];\n    node->ID = IDs++;\n    node->value = 0;\n    node->color = nk_rgb(255, 0, 0);\n    node->input_count = in_count;\n    node->output_count = out_count;\n    node->color = col;\n    node->bounds = bounds;\n    strcpy(node->name, name);\n    node_editor_push(editor, node);\n}\n\nstatic void\nnode_editor_link(struct node_editor *editor, int in_id, int in_slot,\n    int out_id, int out_slot)\n{\n    struct node_link *link;\n    NK_ASSERT((nk_size)editor->link_count < NK_LEN(editor->links));\n    link = &editor->links[editor->link_count++];\n    link->input_id = in_id;\n    link->input_slot = in_slot;\n    link->output_id = out_id;\n    link->output_slot = out_slot;\n}\n\nstatic void\nnode_editor_init(struct node_editor *editor)\n{\n    memset(editor, 0, sizeof(*editor));\n    editor->begin = NULL;\n    editor->end = NULL;\n    node_editor_add(editor, \"Source\", nk_rect(40, 10, 180, 220), nk_rgb(255, 0, 0), 0, 1);\n    node_editor_add(editor, \"Source\", nk_rect(40, 260, 180, 220), nk_rgb(0, 255, 0), 0, 1);\n    node_editor_add(editor, \"Combine\", nk_rect(400, 100, 180, 220), nk_rgb(0,0,255), 2, 2);\n    node_editor_link(editor, 0, 0, 2, 0);\n    node_editor_link(editor, 1, 0, 2, 1);\n    editor->show_grid = nk_true;\n}\n\nstatic int\nnode_editor(struct nk_context *ctx)\n{\n    int n = 0;\n    struct nk_rect total_space;\n    const struct nk_input *in = &ctx->input;\n    struct nk_command_buffer *canvas;\n    struct node *updated = 0;\n    struct node_editor *nodedit = &nodeEditor;\n\n    if (!nodeEditor.initialized) {\n        node_editor_init(&nodeEditor);\n        nodeEditor.initialized = 1;\n    }\n\n    if (nk_begin(ctx, \"NodeEdit\", nk_rect(0, 0, 800, 600),\n        NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE))\n    {\n        /* allocate complete window space */\n        canvas = nk_window_get_canvas(ctx);\n        total_space = nk_window_get_content_region(ctx);\n        nk_layout_space_begin(ctx, NK_STATIC, total_space.h, nodedit->node_count);\n        {\n            struct node *it = nodedit->begin;\n            struct nk_rect size = nk_layout_space_bounds(ctx);\n            struct nk_panel *node = 0;\n\n            if (nodedit->show_grid) {\n                /* display grid */\n                float x, y;\n                const float grid_size = 32.0f;\n                const struct nk_color grid_color = nk_rgb(50, 50, 50);\n                for (x = (float)fmod(size.x - nodedit->scrolling.x, grid_size); x < size.w; x += grid_size)\n                    nk_stroke_line(canvas, x+size.x, size.y, x+size.x, size.y+size.h, 1.0f, grid_color);\n                for (y = (float)fmod(size.y - nodedit->scrolling.y, grid_size); y < size.h; y += grid_size)\n                    nk_stroke_line(canvas, size.x, y+size.y, size.x+size.w, y+size.y, 1.0f, grid_color);\n            }\n\n            /* execute each node as a movable group */\n            while (it) {\n                /* calculate scrolled node window position and size */\n                nk_layout_space_push(ctx, nk_rect(it->bounds.x - nodedit->scrolling.x,\n                    it->bounds.y - nodedit->scrolling.y, it->bounds.w, it->bounds.h));\n\n                /* execute node window */\n                if (nk_group_begin(ctx, it->name, NK_WINDOW_MOVABLE|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_TITLE))\n                {\n                    /* always have last selected node on top */\n\n                    node = nk_window_get_panel(ctx);\n                    if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, node->bounds) &&\n                        (!(it->prev && nk_input_mouse_clicked(in, NK_BUTTON_LEFT,\n                        nk_layout_space_rect_to_screen(ctx, node->bounds)))) &&\n                        nodedit->end != it)\n                    {\n                        updated = it;\n                    }\n\n                    /* ================= NODE CONTENT =====================*/\n                    nk_layout_row_dynamic(ctx, 25, 1);\n                    nk_button_color(ctx, it->color);\n                    it->color.r = (nk_byte)nk_propertyi(ctx, \"#R:\", 0, it->color.r, 255, 1,1);\n                    it->color.g = (nk_byte)nk_propertyi(ctx, \"#G:\", 0, it->color.g, 255, 1,1);\n                    it->color.b = (nk_byte)nk_propertyi(ctx, \"#B:\", 0, it->color.b, 255, 1,1);\n                    it->color.a = (nk_byte)nk_propertyi(ctx, \"#A:\", 0, it->color.a, 255, 1,1);\n                    /* ====================================================*/\n                    nk_group_end(ctx);\n                }\n                {\n                    /* node connector and linking */\n                    float space;\n                    struct nk_rect bounds;\n                    bounds = nk_layout_space_rect_to_local(ctx, node->bounds);\n                    bounds.x += nodedit->scrolling.x;\n                    bounds.y += nodedit->scrolling.y;\n                    it->bounds = bounds;\n\n                    /* output connector */\n                    space = node->bounds.h / (float)((it->output_count) + 1);\n                    for (n = 0; n < it->output_count; ++n) {\n                        struct nk_rect circle;\n                        circle.x = node->bounds.x + node->bounds.w-4;\n                        circle.y = node->bounds.y + space * (float)(n+1);\n                        circle.w = 8; circle.h = 8;\n                        nk_fill_circle(canvas, circle, nk_rgb(100, 100, 100));\n\n                        /* start linking process */\n                        if (nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, circle, nk_true)) {\n                            nodedit->linking.active = nk_true;\n                            nodedit->linking.node = it;\n                            nodedit->linking.input_id = it->ID;\n                            nodedit->linking.input_slot = n;\n                        }\n\n                        /* draw curve from linked node slot to mouse position */\n                        if (nodedit->linking.active && nodedit->linking.node == it &&\n                            nodedit->linking.input_slot == n) {\n                            struct nk_vec2 l0 = nk_vec2(circle.x + 3, circle.y + 3);\n                            struct nk_vec2 l1 = in->mouse.pos;\n                            nk_stroke_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y,\n                                l1.x - 50.0f, l1.y, l1.x, l1.y, 1.0f, nk_rgb(100, 100, 100));\n                        }\n                    }\n\n                    /* input connector */\n                    space = node->bounds.h / (float)((it->input_count) + 1);\n                    for (n = 0; n < it->input_count; ++n) {\n                        struct nk_rect circle;\n                        circle.x = node->bounds.x-4;\n                        circle.y = node->bounds.y + space * (float)(n+1);\n                        circle.w = 8; circle.h = 8;\n                        nk_fill_circle(canvas, circle, nk_rgb(100, 100, 100));\n                        if (nk_input_is_mouse_released(in, NK_BUTTON_LEFT) &&\n                            nk_input_is_mouse_hovering_rect(in, circle) &&\n                            nodedit->linking.active && nodedit->linking.node != it) {\n                            nodedit->linking.active = nk_false;\n                            node_editor_link(nodedit, nodedit->linking.input_id,\n                                nodedit->linking.input_slot, it->ID, n);\n                        }\n                    }\n                }\n                it = it->next;\n            }\n\n            /* reset linking connection */\n            if (nodedit->linking.active && nk_input_is_mouse_released(in, NK_BUTTON_LEFT)) {\n                nodedit->linking.active = nk_false;\n                nodedit->linking.node = NULL;\n                fprintf(stdout, \"linking failed\\n\");\n            }\n\n            /* draw each link */\n            for (n = 0; n < nodedit->link_count; ++n) {\n                struct node_link *link = &nodedit->links[n];\n                struct node *ni = node_editor_find(nodedit, link->input_id);\n                struct node *no = node_editor_find(nodedit, link->output_id);\n                float spacei = node->bounds.h / (float)((ni->output_count) + 1);\n                float spaceo = node->bounds.h / (float)((no->input_count) + 1);\n                struct nk_vec2 l0 = nk_layout_space_to_screen(ctx,\n                    nk_vec2(ni->bounds.x + ni->bounds.w, 3.0f + ni->bounds.y + spacei * (float)(link->input_slot+1)));\n                struct nk_vec2 l1 = nk_layout_space_to_screen(ctx,\n                    nk_vec2(no->bounds.x, 3.0f + no->bounds.y + spaceo * (float)(link->output_slot+1)));\n\n                l0.x -= nodedit->scrolling.x;\n                l0.y -= nodedit->scrolling.y;\n                l1.x -= nodedit->scrolling.x;\n                l1.y -= nodedit->scrolling.y;\n                nk_stroke_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y,\n                    l1.x - 50.0f, l1.y, l1.x, l1.y, 1.0f, nk_rgb(100, 100, 100));\n            }\n\n            if (updated) {\n                /* reshuffle nodes to have least recently selected node on top */\n                node_editor_pop(nodedit, updated);\n                node_editor_push(nodedit, updated);\n            }\n\n            /* node selection */\n            if (nk_input_mouse_clicked(in, NK_BUTTON_LEFT, nk_layout_space_bounds(ctx))) {\n                it = nodedit->begin;\n                nodedit->selected = NULL;\n                nodedit->bounds = nk_rect(in->mouse.pos.x, in->mouse.pos.y, 100, 200);\n                while (it) {\n                    struct nk_rect b = nk_layout_space_rect_to_screen(ctx, it->bounds);\n                    b.x -= nodedit->scrolling.x;\n                    b.y -= nodedit->scrolling.y;\n                    if (nk_input_is_mouse_hovering_rect(in, b))\n                        nodedit->selected = it;\n                    it = it->next;\n                }\n            }\n\n            /* contextual menu */\n            if (nk_contextual_begin(ctx, 0, nk_vec2(100, 220), nk_window_get_bounds(ctx))) {\n                const char *grid_option[] = {\"Show Grid\", \"Hide Grid\"};\n                nk_layout_row_dynamic(ctx, 25, 1);\n                if (nk_contextual_item_label(ctx, \"New\", NK_TEXT_CENTERED))\n                    node_editor_add(nodedit, \"New\", nk_rect(400, 260, 180, 220),\n                            nk_rgb(255, 255, 255), 1, 2);\n                if (nk_contextual_item_label(ctx, grid_option[nodedit->show_grid],NK_TEXT_CENTERED))\n                    nodedit->show_grid = !nodedit->show_grid;\n                nk_contextual_end(ctx);\n            }\n        }\n        nk_layout_space_end(ctx);\n\n        /* window content scrolling */\n        if (nk_input_is_mouse_hovering_rect(in, nk_window_get_bounds(ctx)) &&\n            nk_input_is_mouse_down(in, NK_BUTTON_MIDDLE)) {\n            nodedit->scrolling.x += in->mouse.delta.x;\n            nodedit->scrolling.y += in->mouse.delta.y;\n        }\n    }\n    nk_end(ctx);\n    return !nk_window_is_closed(ctx, \"NodeEdit\");\n}\n\n"
  },
  {
    "path": "demo/common/overview.c",
    "content": "#include <limits.h> /* INT_MAX */\n#include <time.h> /* struct tm, localtime */\n\nstatic int\noverview(struct nk_context *ctx)\n{\n    /* window flags */\n    static nk_bool show_menu = nk_true;\n    static nk_flags window_flags = NK_WINDOW_TITLE|NK_WINDOW_BORDER|NK_WINDOW_SCALABLE|NK_WINDOW_MOVABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_SCROLL_AUTO_HIDE;\n    nk_flags actual_window_flags = 0;\n\n    /* widget flags */\n    static nk_bool disable_widgets = nk_false;\n\n    /* popups */\n    static enum nk_style_header_align header_align = NK_HEADER_RIGHT;\n    static nk_bool show_app_about = nk_false;\n\n#ifdef INCLUDE_STYLE\n    /* styles */\n    static const char* themes[] = {\"Black\", \"White\", \"Red\", \"Blue\", \"Dark\", \"Dracula\",\n      \"Catppucin Latte\", \"Catppucin Frappe\", \"Catppucin Macchiato\", \"Catppucin Mocha\"};\n    static int current_theme = 0;\n#endif\n\n    /* window flags */\n    ctx->style.window.header.align = header_align;\n\n    actual_window_flags = window_flags;\n    if (!(actual_window_flags & NK_WINDOW_TITLE))\n        actual_window_flags &= ~(NK_WINDOW_MINIMIZABLE|NK_WINDOW_CLOSABLE);\n    if (nk_begin(ctx, \"Overview\", nk_rect(10, 10, 400, 600), actual_window_flags))\n    {\n        if (show_menu)\n        {\n            /* menubar */\n            enum menu_states {MENU_DEFAULT, MENU_WINDOWS};\n            static nk_size mprog = 60;\n            static int mslider = 10;\n            static nk_bool mcheck = nk_true;\n            nk_menubar_begin(ctx);\n\n            /* menu #1 */\n            nk_layout_row_begin(ctx, NK_STATIC, 25, 5);\n            nk_layout_row_push(ctx, 45);\n            if (nk_menu_begin_label(ctx, \"MENU\", NK_TEXT_LEFT, nk_vec2(120, 200)))\n            {\n                static size_t prog = 40;\n                static int slider = 10;\n                static nk_bool check = nk_true;\n                nk_layout_row_dynamic(ctx, 25, 1);\n                if (nk_menu_item_label(ctx, \"Hide\", NK_TEXT_LEFT))\n                    show_menu = nk_false;\n                if (nk_menu_item_label(ctx, \"About\", NK_TEXT_LEFT))\n                    show_app_about = nk_true;\n                nk_progress(ctx, &prog, 100, NK_MODIFIABLE);\n                nk_slider_int(ctx, 0, &slider, 16, 1);\n                nk_checkbox_label(ctx, \"check\", &check);\n                nk_menu_end(ctx);\n            }\n            /* menu #2 */\n            nk_layout_row_push(ctx, 60);\n            if (nk_menu_begin_label(ctx, \"ADVANCED\", NK_TEXT_LEFT, nk_vec2(200, 600)))\n            {\n                enum menu_state {MENU_NONE,MENU_FILE, MENU_EDIT,MENU_VIEW,MENU_CHART};\n                static enum menu_state menu_state = MENU_NONE;\n                enum nk_collapse_states state;\n\n                state = (menu_state == MENU_FILE) ? NK_MAXIMIZED: NK_MINIMIZED;\n                if (nk_tree_state_push(ctx, NK_TREE_TAB, \"FILE\", &state)) {\n                    menu_state = MENU_FILE;\n                    nk_menu_item_label(ctx, \"New\", NK_TEXT_LEFT);\n                    nk_menu_item_label(ctx, \"Open\", NK_TEXT_LEFT);\n                    nk_menu_item_label(ctx, \"Save\", NK_TEXT_LEFT);\n                    nk_menu_item_label(ctx, \"Close\", NK_TEXT_LEFT);\n                    nk_menu_item_label(ctx, \"Exit\", NK_TEXT_LEFT);\n                    nk_tree_pop(ctx);\n                } else menu_state = (menu_state == MENU_FILE) ? MENU_NONE: menu_state;\n\n                state = (menu_state == MENU_EDIT) ? NK_MAXIMIZED: NK_MINIMIZED;\n                if (nk_tree_state_push(ctx, NK_TREE_TAB, \"EDIT\", &state)) {\n                    menu_state = MENU_EDIT;\n                    nk_menu_item_label(ctx, \"Copy\", NK_TEXT_LEFT);\n                    nk_menu_item_label(ctx, \"Delete\", NK_TEXT_LEFT);\n                    nk_menu_item_label(ctx, \"Cut\", NK_TEXT_LEFT);\n                    nk_menu_item_label(ctx, \"Paste\", NK_TEXT_LEFT);\n                    nk_tree_pop(ctx);\n                } else menu_state = (menu_state == MENU_EDIT) ? MENU_NONE: menu_state;\n\n                state = (menu_state == MENU_VIEW) ? NK_MAXIMIZED: NK_MINIMIZED;\n                if (nk_tree_state_push(ctx, NK_TREE_TAB, \"VIEW\", &state)) {\n                    menu_state = MENU_VIEW;\n                    nk_menu_item_label(ctx, \"About\", NK_TEXT_LEFT);\n                    nk_menu_item_label(ctx, \"Options\", NK_TEXT_LEFT);\n                    nk_menu_item_label(ctx, \"Customize\", NK_TEXT_LEFT);\n                    nk_tree_pop(ctx);\n                } else menu_state = (menu_state == MENU_VIEW) ? MENU_NONE: menu_state;\n\n                state = (menu_state == MENU_CHART) ? NK_MAXIMIZED: NK_MINIMIZED;\n                if (nk_tree_state_push(ctx, NK_TREE_TAB, \"CHART\", &state)) {\n                    size_t i = 0;\n                    const float values[]={26.0f,13.0f,30.0f,15.0f,25.0f,10.0f,20.0f,40.0f,12.0f,8.0f,22.0f,28.0f};\n                    menu_state = MENU_CHART;\n                    nk_layout_row_dynamic(ctx, 150, 1);\n                    nk_chart_begin(ctx, NK_CHART_COLUMN, NK_LEN(values), 0, 50);\n                    for (i = 0; i < NK_LEN(values); ++i)\n                        nk_chart_push(ctx, values[i]);\n                    nk_chart_end(ctx);\n                    nk_tree_pop(ctx);\n                } else menu_state = (menu_state == MENU_CHART) ? MENU_NONE: menu_state;\n                nk_menu_end(ctx);\n            }\n            /* menu widgets */\n            nk_layout_row_push(ctx, 70);\n            nk_progress(ctx, &mprog, 100, NK_MODIFIABLE);\n            nk_slider_int(ctx, 0, &mslider, 16, 1);\n            nk_checkbox_label(ctx, \"check\", &mcheck);\n            nk_menubar_end(ctx);\n        }\n\n        if (show_app_about)\n        {\n            /* about popup */\n            static struct nk_rect s = {20, 100, 300, 190};\n            if (nk_popup_begin(ctx, NK_POPUP_STATIC, \"About\", NK_WINDOW_CLOSABLE, s))\n            {\n                nk_layout_row_dynamic(ctx, 20, 1);\n                nk_label(ctx, \"Nuklear\", NK_TEXT_LEFT);\n                nk_label(ctx, \"By Micha Mettke\", NK_TEXT_LEFT);\n                nk_label(ctx, \"nuklear is licensed under the public domain License.\",  NK_TEXT_LEFT);\n                nk_popup_end(ctx);\n            } else show_app_about = nk_false;\n        }\n\n#ifdef INCLUDE_STYLE\n        /* style selector */\n        nk_layout_row_dynamic(ctx, 0, 2);\n        {\n            int new_theme;\n            nk_label(ctx, \"Style:\", NK_TEXT_LEFT);\n            new_theme = nk_combo(ctx, themes, NK_LEN(themes), current_theme, 25, nk_vec2(200, 200));\n            if (new_theme != current_theme) {\n                current_theme = new_theme;\n                set_style(ctx, current_theme);\n            }\n        }\n#endif\n\n        /* window flags */\n        if (nk_tree_push(ctx, NK_TREE_TAB, \"Window\", NK_MINIMIZED)) {\n            nk_layout_row_dynamic(ctx, 30, 2);\n            nk_checkbox_label(ctx, \"Menu\", &show_menu);\n            nk_checkbox_flags_label(ctx, \"Titlebar\", &window_flags, NK_WINDOW_TITLE);\n            nk_checkbox_flags_label(ctx, \"Border\", &window_flags, NK_WINDOW_BORDER);\n            nk_checkbox_flags_label(ctx, \"Resizable\", &window_flags, NK_WINDOW_SCALABLE);\n            nk_checkbox_flags_label(ctx, \"Movable\", &window_flags, NK_WINDOW_MOVABLE);\n            nk_checkbox_flags_label(ctx, \"No Scrollbar\", &window_flags, NK_WINDOW_NO_SCROLLBAR);\n            nk_checkbox_flags_label(ctx, \"Minimizable\", &window_flags, NK_WINDOW_MINIMIZABLE);\n            nk_checkbox_flags_label(ctx, \"Scale Left\", &window_flags, NK_WINDOW_SCALE_LEFT);\n            nk_checkbox_label(ctx, \"Disable widgets\", &disable_widgets);\n            nk_tree_pop(ctx);\n        }\n\n        if (disable_widgets)\n        \tnk_widget_disable_begin(ctx);\n\n        if (nk_tree_push(ctx, NK_TREE_TAB, \"Widgets\", NK_MINIMIZED))\n        {\n            enum options {A,B,C};\n            static nk_bool checkbox_left_text_left;\n            static nk_bool checkbox_centered_text_right;\n            static nk_bool checkbox_right_text_right;\n            static nk_bool checkbox_right_text_left;\n            static int option_left;\n            static int option_right;\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Text\", NK_MINIMIZED))\n            {\n                /* Text Widgets */\n                nk_layout_row_dynamic(ctx, 20, 1);\n                nk_label(ctx, \"Label aligned left\", NK_TEXT_LEFT);\n                nk_label(ctx, \"Label aligned centered\", NK_TEXT_CENTERED);\n                nk_label(ctx, \"Label aligned right\", NK_TEXT_RIGHT);\n                nk_label_colored(ctx, \"Blue text\", NK_TEXT_LEFT, nk_rgb(0,0,255));\n                nk_label_colored(ctx, \"Yellow text\", NK_TEXT_LEFT, nk_rgb(255,255,0));\n                nk_text(ctx, \"Text without /0\", 15, NK_TEXT_RIGHT);\n\n                nk_layout_row_static(ctx, 100, 200, 1);\n                nk_label_wrap(ctx, \"This is a very long line to hopefully get this text to be wrapped into multiple lines to show line wrapping\");\n                nk_layout_row_dynamic(ctx, 100, 1);\n                nk_label_wrap(ctx, \"This is another long text to show dynamic window changes on multiline text\");\n                nk_tree_pop(ctx);\n            }\n\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Button\", NK_MINIMIZED))\n            {\n                /* Buttons Widgets */\n                nk_layout_row_static(ctx, 30, 100, 3);\n                if (nk_button_label(ctx, \"Button\"))\n                    fprintf(stdout, \"Button pressed!\\n\");\n                nk_button_set_behavior(ctx, NK_BUTTON_REPEATER);\n                if (nk_button_label(ctx, \"Repeater\"))\n                    fprintf(stdout, \"Repeater is being pressed!\\n\");\n                nk_button_set_behavior(ctx, NK_BUTTON_DEFAULT);\n                nk_button_color(ctx, nk_rgb(0,0,255));\n\n                nk_layout_row_static(ctx, 25, 25, 8);\n                nk_button_symbol(ctx, NK_SYMBOL_CIRCLE_SOLID);\n                nk_button_symbol(ctx, NK_SYMBOL_CIRCLE_OUTLINE);\n                nk_button_symbol(ctx, NK_SYMBOL_RECT_SOLID);\n                nk_button_symbol(ctx, NK_SYMBOL_RECT_OUTLINE);\n                nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_UP);\n                nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_UP_OUTLINE);\n                nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_DOWN);\n                nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_DOWN_OUTLINE);\n                nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_LEFT);\n                nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_LEFT_OUTLINE);\n                nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_RIGHT);\n                nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_RIGHT_OUTLINE);\n\n                nk_layout_row_static(ctx, 30, 100, 2);\n                nk_button_symbol_label(ctx, NK_SYMBOL_TRIANGLE_LEFT, \"prev\", NK_TEXT_RIGHT);\n                nk_button_symbol_label(ctx, NK_SYMBOL_TRIANGLE_RIGHT, \"next\", NK_TEXT_LEFT);\n\n                nk_tree_pop(ctx);\n            }\n\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Basic\", NK_MINIMIZED))\n            {\n                /* Basic widgets */\n                static int int_slider = 5;\n                static float float_slider = 2.5f;\n                static int int_knob = 5;\n                static float float_knob = 2.5f;\n                static nk_size prog_value = 40;\n                static float property_float = 2;\n                static int property_int = 10;\n                static int property_neg = 10;\n\n                static float range_float_min = 0;\n                static float range_float_max = 100;\n                static float range_float_value = 50;\n                static int range_int_min = 0;\n                static int range_int_value = 2048;\n                static int range_int_max = 4096;\n                static const float ratio[] = {120, 150};\n                static int range_int_value_hidden = 2048;\n\n                nk_layout_row_dynamic(ctx, 0, 1);\n                nk_checkbox_label(ctx, \"CheckLeft TextLeft\", &checkbox_left_text_left);\n                nk_checkbox_label_align(ctx, \"CheckCenter TextRight\", &checkbox_centered_text_right, NK_WIDGET_ALIGN_CENTERED | NK_WIDGET_ALIGN_MIDDLE, NK_TEXT_RIGHT);\n                nk_checkbox_label_align(ctx, \"CheckRight TextRight\", &checkbox_right_text_right, NK_WIDGET_LEFT, NK_TEXT_RIGHT);\n                nk_checkbox_label_align(ctx, \"CheckRight TextLeft\", &checkbox_right_text_left, NK_WIDGET_RIGHT, NK_TEXT_LEFT);\n\n                nk_layout_row_static(ctx, 30, 80, 3);\n                option_left = nk_option_label(ctx, \"optionA\", option_left == A) ? A : option_left;\n                option_left = nk_option_label(ctx, \"optionB\", option_left == B) ? B : option_left;\n                option_left = nk_option_label(ctx, \"optionC\", option_left == C) ? C : option_left;\n\n                nk_layout_row_static(ctx, 30, 80, 3);\n                option_right = nk_option_label_align(ctx, \"optionA\", option_right == A, NK_WIDGET_RIGHT, NK_TEXT_RIGHT) ? A : option_right;\n                option_right = nk_option_label_align(ctx, \"optionB\", option_right == B, NK_WIDGET_RIGHT, NK_TEXT_RIGHT) ? B : option_right;\n                option_right = nk_option_label_align(ctx, \"optionC\", option_right == C, NK_WIDGET_RIGHT, NK_TEXT_RIGHT) ? C : option_right;\n\n                nk_layout_row(ctx, NK_STATIC, 30, 2, ratio);\n                nk_labelf(ctx, NK_TEXT_LEFT, \"Slider int\");\n                nk_slider_int(ctx, 0, &int_slider, 10, 1);\n\n                nk_label(ctx, \"Slider float\", NK_TEXT_LEFT);\n                nk_slider_float(ctx, 0, &float_slider, 5.0, 0.5f);\n                nk_labelf(ctx, NK_TEXT_LEFT, \"Progressbar: %u\" , (int)prog_value);\n                nk_progress(ctx, &prog_value, 100, NK_MODIFIABLE);\n\n                nk_layout_row(ctx, NK_STATIC, 40, 2, ratio);\n                nk_labelf(ctx, NK_TEXT_LEFT, \"Knob int: %d\", int_knob);\n                nk_knob_int(ctx, 0, &int_knob, 10, 1, NK_DOWN, 60.0f);\n                nk_labelf(ctx, NK_TEXT_LEFT, \"Knob float: %.2f\", float_knob);\n                nk_knob_float(ctx, 0, &float_knob, 5.0, 0.5f, NK_DOWN, 60.0f);\n\n                nk_layout_row(ctx, NK_STATIC, 25, 2, ratio);\n                nk_label(ctx, \"Property float:\", NK_TEXT_LEFT);\n                nk_property_float(ctx, \"Float:\", 0, &property_float, 64.0f, 0.1f, 0.2f);\n                nk_label(ctx, \"Property int:\", NK_TEXT_LEFT);\n                nk_property_int(ctx, \"Int:\", 0, &property_int, 100, 1, 1);\n                nk_label(ctx, \"Property neg:\", NK_TEXT_LEFT);\n                nk_property_int(ctx, \"Neg:\", -10, &property_neg, 10, 1, 1);\n\n                nk_layout_row_dynamic(ctx, 25, 1);\n                nk_label(ctx, \"Range:\", NK_TEXT_LEFT);\n                nk_layout_row_dynamic(ctx, 25, 3);\n                nk_property_float(ctx, \"#min:\", 0, &range_float_min, range_float_max, 1.0f, 0.2f);\n                nk_property_float(ctx, \"#float:\", range_float_min, &range_float_value, range_float_max, 1.0f, 0.2f);\n                nk_property_float(ctx, \"#max:\", range_float_min, &range_float_max, 100, 1.0f, 0.2f);\n\n                nk_property_int(ctx, \"#min:\", INT_MIN, &range_int_min, range_int_max, 1, 10);\n                nk_property_int(ctx, \"#neg:\", range_int_min, &range_int_value, range_int_max, 1, 10);\n                nk_property_int(ctx, \"#max:\", range_int_min, &range_int_max, INT_MAX, 1, 10);\n\n                nk_layout_row_dynamic(ctx, 0, 2);\n                nk_label(ctx, \"Hidden Label:\", NK_TEXT_LEFT);\n                nk_property_int(ctx, \"##Hidden Label\", range_int_min, &range_int_value_hidden, INT_MAX, 1, 10);\n\n                nk_tree_pop(ctx);\n            }\n\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Inactive\", NK_MINIMIZED))\n            {\n                static nk_bool inactive = 1;\n                nk_layout_row_dynamic(ctx, 30, 1);\n                nk_checkbox_label(ctx, \"Inactive\", &inactive);\n\n                nk_layout_row_static(ctx, 30, 80, 1);\n                if (inactive) {\n                    nk_widget_disable_begin(ctx);\n                }\n\n                if (nk_button_label(ctx, \"button\"))\n                    fprintf(stdout, \"button pressed\\n\");\n\n                nk_widget_disable_end(ctx);\n\n                nk_tree_pop(ctx);\n            }\n\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Selectable\", NK_MINIMIZED))\n            {\n                if (nk_tree_push(ctx, NK_TREE_NODE, \"List\", NK_MINIMIZED))\n                {\n                    static nk_bool selected[4] = {nk_false, nk_false, nk_true, nk_false};\n                    nk_layout_row_static(ctx, 18, 100, 1);\n                    nk_selectable_label(ctx, \"Selectable\", NK_TEXT_LEFT, &selected[0]);\n                    nk_selectable_label(ctx, \"Selectable\", NK_TEXT_LEFT, &selected[1]);\n                    nk_label(ctx, \"Not Selectable\", NK_TEXT_LEFT);\n                    nk_selectable_label(ctx, \"Selectable\", NK_TEXT_LEFT, &selected[2]);\n                    nk_selectable_label(ctx, \"Selectable\", NK_TEXT_LEFT, &selected[3]);\n                    nk_tree_pop(ctx);\n                }\n                if (nk_tree_push(ctx, NK_TREE_NODE, \"Grid\", NK_MINIMIZED))\n                {\n                    int i;\n                    static nk_bool selected[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1};\n                    nk_layout_row_static(ctx, 50, 50, 4);\n                    for (i = 0; i < 16; ++i) {\n                        if (nk_selectable_label(ctx, \"Z\", NK_TEXT_CENTERED, &selected[i])) {\n                            int x = (i % 4), y = i / 4;\n                            if (x > 0) selected[i - 1] ^= 1;\n                            if (x < 3) selected[i + 1] ^= 1;\n                            if (y > 0) selected[i - 4] ^= 1;\n                            if (y < 3) selected[i + 4] ^= 1;\n                        }\n                    }\n                    nk_tree_pop(ctx);\n                }\n                nk_tree_pop(ctx);\n            }\n\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Combo\", NK_MINIMIZED))\n            {\n                /* Combobox Widgets\n                 * In this library comboboxes are not limited to being a popup\n                 * list of selectable text. Instead it is a abstract concept of\n                 * having something that is *selected* or displayed, a popup window\n                 * which opens if something needs to be modified and the content\n                 * of the popup which causes the *selected* or displayed value to\n                 * change or if wanted close the combobox.\n                 *\n                 * While strange at first handling comboboxes in a abstract way\n                 * solves the problem of overloaded window content. For example\n                 * changing a color value requires 4 value modifier (slider, property,...)\n                 * for RGBA then you need a label and ways to display the current color.\n                 * If you want to go fancy you even add rgb and hsv ratio boxes.\n                 * While fine for one color if you have a lot of them it because\n                 * tedious to look at and quite wasteful in space. You could add\n                 * a popup which modifies the color but this does not solve the\n                 * fact that it still requires a lot of cluttered space to do.\n                 *\n                 * In these kind of instance abstract comboboxes are quite handy. All\n                 * value modifiers are hidden inside the combobox popup and only\n                 * the color is shown if not open. This combines the clarity of the\n                 * popup with the ease of use of just using the space for modifiers.\n                 *\n                 * Other instances are for example time and especially date picker,\n                 * which only show the currently activated time/data and hide the\n                 * selection logic inside the combobox popup.\n                 */\n                static float chart_selection = 8.0f;\n                static int current_weapon = 0;\n                static nk_bool check_values[5];\n                static float position[3];\n                static struct nk_color combo_color = {130, 50, 50, 255};\n                static struct nk_colorf combo_color2 = {0.509f, 0.705f, 0.2f, 1.0f};\n                static size_t prog_a =  20, prog_b = 40, prog_c = 10, prog_d = 90;\n                static const char *weapons[] = {\"Fist\",\"Pistol\",\"Shotgun\",\"Plasma\",\"BFG\"};\n\n                char buffer[64];\n                size_t sum = 0;\n\n                /* default combobox */\n                nk_layout_row_static(ctx, 25, 200, 1);\n                current_weapon = nk_combo(ctx, weapons, NK_LEN(weapons), current_weapon, 25, nk_vec2(200,200));\n\n                /* slider color combobox */\n                if (nk_combo_begin_color(ctx, combo_color, nk_vec2(200,200))) {\n                    float ratios[] = {0.15f, 0.85f};\n                    nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratios);\n                    nk_label(ctx, \"R:\", NK_TEXT_LEFT);\n                    combo_color.r = (nk_byte)nk_slide_int(ctx, 0, combo_color.r, 255, 5);\n                    nk_label(ctx, \"G:\", NK_TEXT_LEFT);\n                    combo_color.g = (nk_byte)nk_slide_int(ctx, 0, combo_color.g, 255, 5);\n                    nk_label(ctx, \"B:\", NK_TEXT_LEFT);\n                    combo_color.b = (nk_byte)nk_slide_int(ctx, 0, combo_color.b, 255, 5);\n                    nk_label(ctx, \"A:\", NK_TEXT_LEFT);\n                    combo_color.a = (nk_byte)nk_slide_int(ctx, 0, combo_color.a , 255, 5);\n                    nk_combo_end(ctx);\n                }\n                /* complex color combobox */\n                if (nk_combo_begin_color(ctx, nk_rgb_cf(combo_color2), nk_vec2(200,400))) {\n                    enum color_mode {COL_RGB, COL_HSV};\n                    static int col_mode = COL_RGB;\n                    #ifndef DEMO_DO_NOT_USE_COLOR_PICKER\n                    nk_layout_row_dynamic(ctx, 120, 1);\n                    combo_color2 = nk_color_picker(ctx, combo_color2, NK_RGBA);\n                    #endif\n\n                    nk_layout_row_dynamic(ctx, 25, 2);\n                    col_mode = nk_option_label(ctx, \"RGB\", col_mode == COL_RGB) ? COL_RGB : col_mode;\n                    col_mode = nk_option_label(ctx, \"HSV\", col_mode == COL_HSV) ? COL_HSV : col_mode;\n\n                    nk_layout_row_dynamic(ctx, 25, 1);\n                    if (col_mode == COL_RGB) {\n                        combo_color2.r = nk_propertyf(ctx, \"#R:\", 0, combo_color2.r, 1.0f, 0.01f,0.005f);\n                        combo_color2.g = nk_propertyf(ctx, \"#G:\", 0, combo_color2.g, 1.0f, 0.01f,0.005f);\n                        combo_color2.b = nk_propertyf(ctx, \"#B:\", 0, combo_color2.b, 1.0f, 0.01f,0.005f);\n                        combo_color2.a = nk_propertyf(ctx, \"#A:\", 0, combo_color2.a, 1.0f, 0.01f,0.005f);\n                    } else {\n                        float hsva[4];\n                        nk_colorf_hsva_fv(hsva, combo_color2);\n                        hsva[0] = nk_propertyf(ctx, \"#H:\", 0, hsva[0], 1.0f, 0.01f,0.05f);\n                        hsva[1] = nk_propertyf(ctx, \"#S:\", 0, hsva[1], 1.0f, 0.01f,0.05f);\n                        hsva[2] = nk_propertyf(ctx, \"#V:\", 0, hsva[2], 1.0f, 0.01f,0.05f);\n                        hsva[3] = nk_propertyf(ctx, \"#A:\", 0, hsva[3], 1.0f, 0.01f,0.05f);\n                        combo_color2 = nk_hsva_colorfv(hsva);\n                    }\n                    nk_combo_end(ctx);\n                }\n                /* progressbar combobox */\n                sum = prog_a + prog_b + prog_c + prog_d;\n                sprintf(buffer, \"%lu\", sum);\n                if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,200))) {\n                    nk_layout_row_dynamic(ctx, 30, 1);\n                    nk_progress(ctx, &prog_a, 100, NK_MODIFIABLE);\n                    nk_progress(ctx, &prog_b, 100, NK_MODIFIABLE);\n                    nk_progress(ctx, &prog_c, 100, NK_MODIFIABLE);\n                    nk_progress(ctx, &prog_d, 100, NK_MODIFIABLE);\n                    nk_combo_end(ctx);\n                }\n\n                /* checkbox combobox */\n                sum = (size_t)(check_values[0] + check_values[1] + check_values[2] + check_values[3] + check_values[4]);\n                sprintf(buffer, \"%lu\", sum);\n                if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,200))) {\n                    nk_layout_row_dynamic(ctx, 30, 1);\n                    nk_checkbox_label(ctx, weapons[0], &check_values[0]);\n                    nk_checkbox_label(ctx, weapons[1], &check_values[1]);\n                    nk_checkbox_label(ctx, weapons[2], &check_values[2]);\n                    nk_checkbox_label(ctx, weapons[3], &check_values[3]);\n                    nk_combo_end(ctx);\n                }\n\n                /* complex text combobox */\n                sprintf(buffer, \"%.2f, %.2f, %.2f\", position[0], position[1],position[2]);\n                if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,200))) {\n                    nk_layout_row_dynamic(ctx, 25, 1);\n                    nk_property_float(ctx, \"#X:\", -1024.0f, &position[0], 1024.0f, 1,0.5f);\n                    nk_property_float(ctx, \"#Y:\", -1024.0f, &position[1], 1024.0f, 1,0.5f);\n                    nk_property_float(ctx, \"#Z:\", -1024.0f, &position[2], 1024.0f, 1,0.5f);\n                    nk_combo_end(ctx);\n                }\n\n                /* chart combobox */\n                sprintf(buffer, \"%.1f\", chart_selection);\n                if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,250))) {\n                    size_t i = 0;\n                    static const float values[]={26.0f,13.0f,30.0f,15.0f,25.0f,10.0f,20.0f,40.0f, 12.0f, 8.0f, 22.0f, 28.0f, 5.0f};\n                    nk_layout_row_dynamic(ctx, 150, 1);\n                    nk_chart_begin(ctx, NK_CHART_COLUMN, NK_LEN(values), 0, 50);\n                    for (i = 0; i < NK_LEN(values); ++i) {\n                        nk_flags res = nk_chart_push(ctx, values[i]);\n                        if (res & NK_CHART_CLICKED) {\n                            chart_selection = values[i];\n                            nk_combo_close(ctx);\n                        }\n                    }\n                    nk_chart_end(ctx);\n                    nk_combo_end(ctx);\n                }\n\n                {\n                    static int time_selected = 0;\n                    static int date_selected = 0;\n                    static struct tm sel_time;\n                    static struct tm sel_date;\n                    if (!time_selected || !date_selected) {\n                        /* keep time and date updated if nothing is selected */\n                        time_t cur_time = time(0);\n                        struct tm *n = localtime(&cur_time);\n                        if (!time_selected)\n                            memcpy(&sel_time, n, sizeof(struct tm));\n                        if (!date_selected)\n                            memcpy(&sel_date, n, sizeof(struct tm));\n                    }\n\n                    /* time combobox */\n                    sprintf(buffer, \"%02d:%02d:%02d\", sel_time.tm_hour, sel_time.tm_min, sel_time.tm_sec);\n                    if (nk_combo_begin_label(ctx, buffer, nk_vec2(200,250))) {\n                        time_selected = 1;\n                        nk_layout_row_dynamic(ctx, 25, 1);\n                        sel_time.tm_sec = nk_propertyi(ctx, \"#S:\", 0, sel_time.tm_sec, 60, 1, 1);\n                        sel_time.tm_min = nk_propertyi(ctx, \"#M:\", 0, sel_time.tm_min, 60, 1, 1);\n                        sel_time.tm_hour = nk_propertyi(ctx, \"#H:\", 0, sel_time.tm_hour, 23, 1, 1);\n                        nk_combo_end(ctx);\n                    }\n\n                    /* date combobox */\n                    sprintf(buffer, \"%02d-%02d-%02d\", sel_date.tm_mday, sel_date.tm_mon+1, sel_date.tm_year+1900);\n                    if (nk_combo_begin_label(ctx, buffer, nk_vec2(350,400)))\n                    {\n                        int i = 0;\n                        const char *month[] = {\"January\", \"February\", \"March\",\n                            \"April\", \"May\", \"June\", \"July\", \"August\", \"September\",\n                            \"October\", \"November\", \"December\"};\n                        const char *week_days[] = {\"SUN\", \"MON\", \"TUE\", \"WED\", \"THU\", \"FRI\", \"SAT\"};\n                        const int month_days[] = {31,28,31,30,31,30,31,31,30,31,30,31};\n                        int year = sel_date.tm_year+1900;\n                        int leap_year = (!(year % 4) && ((year % 100))) || !(year % 400);\n                        int days = (sel_date.tm_mon == 1) ?\n                            month_days[sel_date.tm_mon] + leap_year:\n                            month_days[sel_date.tm_mon];\n\n                        /* header with month and year */\n                        date_selected = 1;\n                        nk_layout_row_begin(ctx, NK_DYNAMIC, 20, 3);\n                        nk_layout_row_push(ctx, 0.05f);\n                        if (nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_LEFT)) {\n                            if (sel_date.tm_mon == 0) {\n                                sel_date.tm_mon = 11;\n                                sel_date.tm_year = NK_MAX(0, sel_date.tm_year-1);\n                            } else sel_date.tm_mon--;\n                        }\n                        nk_layout_row_push(ctx, 0.9f);\n                        sprintf(buffer, \"%s %d\", month[sel_date.tm_mon], year);\n                        nk_label(ctx, buffer, NK_TEXT_CENTERED);\n                        nk_layout_row_push(ctx, 0.05f);\n                        if (nk_button_symbol(ctx, NK_SYMBOL_TRIANGLE_RIGHT)) {\n                            if (sel_date.tm_mon == 11) {\n                                sel_date.tm_mon = 0;\n                                sel_date.tm_year++;\n                            } else sel_date.tm_mon++;\n                        }\n                        nk_layout_row_end(ctx);\n\n                        /* good old week day formula (double because precision) */\n                        {int year_n = (sel_date.tm_mon < 2) ? year-1: year;\n                        int y = year_n % 100;\n                        int c = year_n / 100;\n                        int y4 = (int)((float)y / 4);\n                        int c4 = (int)((float)c / 4);\n                        int m = (int)(2.6 * (double)(((sel_date.tm_mon + 10) % 12) + 1) - 0.2);\n                        int week_day = (((1 + m + y + y4 + c4 - 2 * c) % 7) + 7) % 7;\n\n                        /* weekdays  */\n                        nk_layout_row_dynamic(ctx, 35, 7);\n                        for (i = 0; i < (int)NK_LEN(week_days); ++i)\n                            nk_label(ctx, week_days[i], NK_TEXT_CENTERED);\n\n                        /* days  */\n                        if (week_day > 0) nk_spacing(ctx, week_day);\n                        for (i = 1; i <= days; ++i) {\n                            sprintf(buffer, \"%d\", i);\n                            if (nk_button_label(ctx, buffer)) {\n                                sel_date.tm_mday = i;\n                                nk_combo_close(ctx);\n                            }\n                        }}\n                        nk_combo_end(ctx);\n                    }\n                }\n\n                nk_tree_pop(ctx);\n            }\n\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Input\", NK_MINIMIZED))\n            {\n                static const float ratio[] = {120, 150};\n                static char field_buffer[64];\n                static char field_w_overwrite_buf[64];\n                static char text[9][64];\n                static int text_len[9];\n                static char box_buffer[512];\n                static int field_len;\n                static int field_ow_len;\n                static int box_len;\n                nk_flags active;\n\n                nk_layout_row(ctx, NK_STATIC, 25, 2, ratio);\n                nk_label(ctx, \"Default:\", NK_TEXT_LEFT);\n\n                nk_edit_string(ctx, NK_EDIT_SIMPLE, text[0], &text_len[0], 64, nk_filter_default);\n                nk_label(ctx, \"Int:\", NK_TEXT_LEFT);\n                nk_edit_string(ctx, NK_EDIT_SIMPLE, text[1], &text_len[1], 64, nk_filter_decimal);\n                nk_label(ctx, \"Float:\", NK_TEXT_LEFT);\n                nk_edit_string(ctx, NK_EDIT_SIMPLE, text[2], &text_len[2], 64, nk_filter_float);\n                nk_label(ctx, \"Hex:\", NK_TEXT_LEFT);\n                nk_edit_string(ctx, NK_EDIT_SIMPLE, text[4], &text_len[4], 64, nk_filter_hex);\n                nk_label(ctx, \"Octal:\", NK_TEXT_LEFT);\n                nk_edit_string(ctx, NK_EDIT_SIMPLE, text[5], &text_len[5], 64, nk_filter_oct);\n                nk_label(ctx, \"Binary:\", NK_TEXT_LEFT);\n                nk_edit_string(ctx, NK_EDIT_SIMPLE, text[6], &text_len[6], 64, nk_filter_binary);\n\n                nk_label(ctx, \"Password:\", NK_TEXT_LEFT);\n                {\n                    int i = 0;\n                    int old_len = text_len[8];\n                    char buffer[64];\n                    for (i = 0; i < text_len[8]; ++i) buffer[i] = '*';\n                    nk_edit_string(ctx, NK_EDIT_FIELD, buffer, &text_len[8], 64, nk_filter_default);\n                    if (old_len < text_len[8])\n                        memcpy(&text[8][old_len], &buffer[old_len], (nk_size)(text_len[8] - old_len));\n                }\n\n                nk_label(ctx, \"Field:\", NK_TEXT_LEFT);\n                nk_edit_string(ctx, NK_EDIT_FIELD, field_buffer, &field_len, 64, nk_filter_default);\n\n                nk_label(ctx, \"Field 2:\", NK_TEXT_LEFT);\n                nk_edit_string(ctx, NK_EDIT_SELECTABLE|NK_EDIT_CLIPBOARD, field_w_overwrite_buf, &field_ow_len, 64, nk_filter_default);\n\n                nk_label(ctx, \"Box:\", NK_TEXT_LEFT);\n                nk_layout_row_static(ctx, 180, 278, 1);\n                nk_edit_string(ctx, NK_EDIT_BOX, box_buffer, &box_len, 512, nk_filter_default);\n\n                nk_layout_row(ctx, NK_STATIC, 25, 2, ratio);\n                active = nk_edit_string(ctx, NK_EDIT_FIELD|NK_EDIT_SIG_ENTER, text[7], &text_len[7], 64,  nk_filter_ascii);\n                if (nk_button_label(ctx, \"Submit\") ||\n                    (active & NK_EDIT_COMMITED))\n                {\n                    text[7][text_len[7]] = '\\n';\n                    text_len[7]++;\n                    memcpy(&box_buffer[box_len], &text[7], (nk_size)text_len[7]);\n                    box_len += text_len[7];\n                    text_len[7] = 0;\n                }\n                nk_tree_pop(ctx);\n            }\n\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Horizontal Rule\", NK_MINIMIZED))\n            {\n                nk_layout_row_dynamic(ctx, 12, 1);\n                nk_label(ctx, \"Use this to subdivide spaces visually\", NK_TEXT_LEFT);\n                nk_layout_row_dynamic(ctx, 4, 1);\n                nk_rule_horizontal(ctx, nk_white, nk_true);\n                nk_layout_row_dynamic(ctx, 75, 1);\n                nk_label_wrap(ctx, \"Best used in 'Card'-like layouts, with a bigger title font on top. Takes on the size of the previous layout definition. Rounding optional.\");\n                nk_tree_pop(ctx);\n            }\n\n            nk_tree_pop(ctx);\n        }\n\n        if (nk_tree_push(ctx, NK_TREE_TAB, \"Chart\", NK_MINIMIZED))\n        {\n            /* Chart Widgets\n             * This library has two different rather simple charts. The line and the\n             * column chart. Both provide a simple way of visualizing values and\n             * have a retained mode and immediate mode API version. For the retain\n             * mode version `nk_plot` and `nk_plot_function` you either provide\n             * an array or a callback to call to handle drawing the graph.\n             * For the immediate mode version you start by calling `nk_chart_begin`\n             * and need to provide min and max values for scaling on the Y-axis.\n             * and then call `nk_chart_push` to push values into the chart.\n             * Finally `nk_chart_end` needs to be called to end the process. */\n            float id = 0;\n            static int col_index = -1;\n            static int line_index = -1;\n            static nk_bool show_markers = nk_true;\n            float step = (2*3.141592654f) / 32;\n\n            int i;\n            int index = -1;\n\n            /* line chart */\n            id = 0;\n            index = -1;\n            nk_layout_row_dynamic(ctx, 15, 1);\n            nk_checkbox_label(ctx, \"Show markers\", &show_markers);\n            nk_layout_row_dynamic(ctx, 100, 1);\n            ctx->style.chart.show_markers = show_markers;\n            if (nk_chart_begin(ctx, NK_CHART_LINES, 32, -1.0f, 1.0f)) {\n                for (i = 0; i < 32; ++i) {\n                    nk_flags res = nk_chart_push(ctx, (float)cos(id));\n                    if (res & NK_CHART_HOVERING)\n                        index = (int)i;\n                    if (res & NK_CHART_CLICKED)\n                        line_index = (int)i;\n                    id += step;\n                }\n                nk_chart_end(ctx);\n            }\n\n            if (index != -1)\n                nk_tooltipf(ctx, \"Value: %.2f\", (float)cos((float)index*step));\n            if (line_index != -1) {\n                nk_layout_row_dynamic(ctx, 20, 1);\n                nk_labelf(ctx, NK_TEXT_LEFT, \"Selected value: %.2f\", (float)cos((float)index*step));\n            }\n\n            /* column chart */\n            nk_layout_row_dynamic(ctx, 100, 1);\n            if (nk_chart_begin(ctx, NK_CHART_COLUMN, 32, 0.0f, 1.0f)) {\n                for (i = 0; i < 32; ++i) {\n                    nk_flags res = nk_chart_push(ctx, (float)fabs(sin(id)));\n                    if (res & NK_CHART_HOVERING)\n                        index = (int)i;\n                    if (res & NK_CHART_CLICKED)\n                        col_index = (int)i;\n                    id += step;\n                }\n                nk_chart_end(ctx);\n            }\n            if (index != -1)\n                nk_tooltipf(ctx, \"Value: %.2f\", (float)fabs(sin(step * (float)index)));\n            if (col_index != -1) {\n                nk_layout_row_dynamic(ctx, 20, 1);\n                nk_labelf(ctx, NK_TEXT_LEFT, \"Selected value: %.2f\", (float)fabs(sin(step * (float)col_index)));\n            }\n\n            /* mixed chart */\n            nk_layout_row_dynamic(ctx, 100, 1);\n            if (nk_chart_begin(ctx, NK_CHART_COLUMN, 32, 0.0f, 1.0f)) {\n                nk_chart_add_slot(ctx, NK_CHART_LINES, 32, -1.0f, 1.0f);\n                nk_chart_add_slot(ctx, NK_CHART_LINES, 32, -1.0f, 1.0f);\n                for (id = 0, i = 0; i < 32; ++i) {\n                    nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);\n                    nk_chart_push_slot(ctx, (float)cos(id), 1);\n                    nk_chart_push_slot(ctx, (float)sin(id), 2);\n                    id += step;\n                }\n            }\n            nk_chart_end(ctx);\n\n            /* mixed colored chart */\n            nk_layout_row_dynamic(ctx, 100, 1);\n            if (nk_chart_begin_colored(ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {\n                nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f);\n                nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,255,0), nk_rgb(0,150,0), 32, -1.0f, 1.0f);\n                for (id = 0, i = 0; i < 32; ++i) {\n                    nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);\n                    nk_chart_push_slot(ctx, (float)cos(id), 1);\n                    nk_chart_push_slot(ctx, (float)sin(id), 2);\n                    id += step;\n                }\n            }\n            nk_chart_end(ctx);\n            nk_tree_pop(ctx);\n        }\n\n        if (nk_tree_push(ctx, NK_TREE_TAB, \"Popup\", NK_MINIMIZED))\n        {\n            static struct nk_color color = {255,0,0, 255};\n            static nk_bool select[4];\n            static nk_bool popup_active;\n            const struct nk_input *in = &ctx->input;\n            struct nk_rect bounds;\n\n            /* menu contextual */\n            nk_layout_row_static(ctx, 30, 160, 1);\n            bounds = nk_widget_bounds(ctx);\n            nk_label(ctx, \"Right click me for menu\", NK_TEXT_LEFT);\n\n            if (nk_contextual_begin(ctx, 0, nk_vec2(100, 300), bounds)) {\n                static size_t prog = 40;\n                static int slider = 10;\n\n                nk_layout_row_dynamic(ctx, 25, 1);\n                nk_checkbox_label(ctx, \"Menu\", &show_menu);\n                nk_progress(ctx, &prog, 100, NK_MODIFIABLE);\n                nk_slider_int(ctx, 0, &slider, 16, 1);\n                if (nk_contextual_item_label(ctx, \"About\", NK_TEXT_CENTERED))\n                    show_app_about = nk_true;\n                nk_selectable_label(ctx, select[0]?\"Unselect\":\"Select\", NK_TEXT_LEFT, &select[0]);\n                nk_selectable_label(ctx, select[1]?\"Unselect\":\"Select\", NK_TEXT_LEFT, &select[1]);\n                nk_selectable_label(ctx, select[2]?\"Unselect\":\"Select\", NK_TEXT_LEFT, &select[2]);\n                nk_selectable_label(ctx, select[3]?\"Unselect\":\"Select\", NK_TEXT_LEFT, &select[3]);\n                nk_contextual_end(ctx);\n            }\n\n            /* color contextual */\n            nk_layout_row_begin(ctx, NK_STATIC, 30, 2);\n            nk_layout_row_push(ctx, 120);\n            nk_label(ctx, \"Right Click here:\", NK_TEXT_LEFT);\n            nk_layout_row_push(ctx, 50);\n            bounds = nk_widget_bounds(ctx);\n            nk_button_color(ctx, color);\n            nk_layout_row_end(ctx);\n\n            if (nk_contextual_begin(ctx, 0, nk_vec2(350, 60), bounds)) {\n                nk_layout_row_dynamic(ctx, 30, 4);\n                color.r = (nk_byte)nk_propertyi(ctx, \"#r\", 0, color.r, 255, 1, 1);\n                color.g = (nk_byte)nk_propertyi(ctx, \"#g\", 0, color.g, 255, 1, 1);\n                color.b = (nk_byte)nk_propertyi(ctx, \"#b\", 0, color.b, 255, 1, 1);\n                color.a = (nk_byte)nk_propertyi(ctx, \"#a\", 0, color.a, 255, 1, 1);\n                nk_contextual_end(ctx);\n            }\n\n            /* popup */\n            nk_layout_row_begin(ctx, NK_STATIC, 30, 2);\n            nk_layout_row_push(ctx, 120);\n            nk_label(ctx, \"Popup:\", NK_TEXT_LEFT);\n            nk_layout_row_push(ctx, 50);\n            if (nk_button_label(ctx, \"Popup\"))\n                popup_active = 1;\n            nk_layout_row_end(ctx);\n\n            if (popup_active)\n            {\n                static struct nk_rect s = {20, 100, 220, 90};\n                if (nk_popup_begin(ctx, NK_POPUP_STATIC, \"Error\", 0, s))\n                {\n                    nk_layout_row_dynamic(ctx, 25, 1);\n                    nk_label(ctx, \"A terrible error as occurred\", NK_TEXT_LEFT);\n                    nk_layout_row_dynamic(ctx, 25, 2);\n                    if (nk_button_label(ctx, \"OK\")) {\n                        popup_active = 0;\n                        nk_popup_close(ctx);\n                    }\n                    if (nk_button_label(ctx, \"Cancel\")) {\n                        popup_active = 0;\n                        nk_popup_close(ctx);\n                    }\n                    nk_popup_end(ctx);\n                } else popup_active = nk_false;\n            }\n\n            /* tooltips */\n            nk_layout_row_static(ctx, 30, 400, 1);\n            bounds = nk_widget_bounds(ctx);\n            nk_label(ctx, \"Hover for default tooltip\", NK_TEXT_LEFT);\n            if (nk_input_is_mouse_hovering_rect(in, bounds)) {\n                nk_tooltip(ctx, \"This is a default tooltip\");\n            }\n            bounds = nk_widget_bounds(ctx);\n            nk_label(ctx, \"Hover for Gnome-like tooltip\", NK_TEXT_LEFT);\n            if (nk_input_is_mouse_hovering_rect(in, bounds)) {\n                struct nk_vec2 offset = { 0, -15 };\n                nk_tooltip_offset(ctx, \"Gnome bottom centers plus a -y offset\", NK_BOTTOM_CENTER, offset);\n            }\n            bounds = nk_widget_bounds(ctx);\n            nk_label(ctx, \"Hover for a bottom left tooltip\", NK_TEXT_LEFT);\n            if (nk_input_is_mouse_hovering_rect(in, bounds)) {\n                struct nk_vec2 offset = { 0, 0 };\n                nk_tooltip_offset(ctx, \"Bottom left positioning\", NK_BOTTOM_LEFT, offset);\n            }\n            bounds = nk_widget_bounds(ctx);\n            nk_label(ctx, \"Hover for MAGIC!\", NK_TEXT_LEFT);\n            if (nk_input_is_mouse_hovering_rect(in, bounds)) {\n                static double accum_time_seconds = 0.0;\n                const double speed = 3.0, radius = 50.0;\n                struct nk_vec2 offset;\n                offset.x = radius * NK_COS(accum_time_seconds * speed);\n                offset.y = radius * NK_SIN(accum_time_seconds * speed);\n                nk_tooltip_offset(ctx, \"WOW!\", NK_MIDDLE_CENTER, offset);\n                accum_time_seconds += (double)(ctx->delta_time_seconds);\n            }\n\n            /* editor for custom tooltip */\n            {\n                static char text_buf[64] = {0};\n                static int text_len = 0;\n                static int text_initialized = 0;\n                static struct nk_vec2 offset = {0};\n                static const char* tooltip_positions[] =\n                {\n                    \"TOP_LEFT\",\n                    \"TOP_CENTER\",\n                    \"TOP_RIGHT\",\n\n                    \"MIDDLE_LEFT\",\n                    \"MIDDLE_CENTER\",\n                    \"MIDDLE_RIGHT\",\n\n                    \"BOTTOM_LEFT\",\n                    \"BOTTOM_CENTER\",\n                    \"BOTTOM_RIGHT\"\n                };\n                static int cur_pos = NK_TOP_LEFT;\n\n                if (!text_initialized) {\n                    const char text_default[] = \"you can customize this!\";\n                    NK_ASSERT(sizeof(text_default) < sizeof(text_buf));\n                    memcpy(text_buf, text_default, sizeof(text_default));\n                    text_len = sizeof(text_default) - 1;\n                    text_initialized = 1;\n                }\n                bounds = nk_widget_bounds(ctx);\n                nk_label(ctx, \"Hover for custom tooltip (you can customize it below)\", NK_TEXT_LEFT);\n                if (nk_input_is_mouse_hovering_rect(in, bounds)) {\n                    nk_tooltip_offset(ctx, text_buf, cur_pos, offset);\n                }\n                nk_layout_row_dynamic(ctx, 1, 1);\n                nk_rule_horizontal(ctx, nk_white, nk_true);\n                nk_layout_row_dynamic(ctx, 30, 2);\n                nk_label(ctx, \"custom tooltip text:\", NK_TEXT_LEFT);\n                nk_edit_string(ctx, NK_EDIT_FIELD, text_buf, &text_len, sizeof(text_buf), nk_filter_default);\n                text_buf[text_len] = '\\0';  /* TODO: why nk_edit_string is NOT setting this on its own? */\n                nk_layout_row_dynamic(ctx, 30, 1);\n                cur_pos = nk_combo(ctx, tooltip_positions, NK_LEN(tooltip_positions), cur_pos, 25, nk_vec2(200, 200));\n\n\n                nk_layout_row_dynamic(ctx, 30, 2);\n                nk_label(ctx, \"custom tooltip offset\", NK_TEXT_LEFT);\n                nk_property_float(ctx, \"x\", -100.0f, &offset.x, 100.0f, 5.0f, 0.5f);\n                nk_label(ctx, \"custom tooltip offset\", NK_TEXT_LEFT);\n                nk_property_float(ctx, \"y\", -100.0f, &offset.y, 100.0f, 5.0f, 0.5f);\n            }\n\n            nk_tree_pop(ctx);\n        }\n\n        if (nk_tree_push(ctx, NK_TREE_TAB, \"Layout\", NK_MINIMIZED))\n        {\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Widget\", NK_MINIMIZED))\n            {\n                float ratio_two[] = {0.2f, 0.6f, 0.2f};\n                float width_two[] = {100, 200, 50};\n\n                nk_layout_row_dynamic(ctx, 30, 1);\n                nk_label(ctx, \"Dynamic fixed column layout with generated position and size:\", NK_TEXT_LEFT);\n                nk_layout_row_dynamic(ctx, 30, 3);\n                nk_button_label(ctx, \"button\");\n                nk_button_label(ctx, \"button\");\n                nk_button_label(ctx, \"button\");\n\n                nk_layout_row_dynamic(ctx, 30, 1);\n                nk_label(ctx, \"static fixed column layout with generated position and size:\", NK_TEXT_LEFT);\n                nk_layout_row_static(ctx, 30, 100, 3);\n                nk_button_label(ctx, \"button\");\n                nk_button_label(ctx, \"button\");\n                nk_button_label(ctx, \"button\");\n\n                nk_layout_row_dynamic(ctx, 30, 1);\n                nk_label(ctx, \"Dynamic array-based custom column layout with generated position and custom size:\",NK_TEXT_LEFT);\n                nk_layout_row(ctx, NK_DYNAMIC, 30, 3, ratio_two);\n                nk_button_label(ctx, \"button\");\n                nk_button_label(ctx, \"button\");\n                nk_button_label(ctx, \"button\");\n\n                nk_layout_row_dynamic(ctx, 30, 1);\n                nk_label(ctx, \"Static array-based custom column layout with generated position and custom size:\",NK_TEXT_LEFT );\n                nk_layout_row(ctx, NK_STATIC, 30, 3, width_two);\n                nk_button_label(ctx, \"button\");\n                nk_button_label(ctx, \"button\");\n                nk_button_label(ctx, \"button\");\n\n                nk_layout_row_dynamic(ctx, 30, 1);\n                nk_label(ctx, \"Dynamic immediate mode custom column layout with generated position and custom size:\",NK_TEXT_LEFT);\n                nk_layout_row_begin(ctx, NK_DYNAMIC, 30, 3);\n                nk_layout_row_push(ctx, 0.2f);\n                nk_button_label(ctx, \"button\");\n                nk_layout_row_push(ctx, 0.6f);\n                nk_button_label(ctx, \"button\");\n                nk_layout_row_push(ctx, 0.2f);\n                nk_button_label(ctx, \"button\");\n                nk_layout_row_end(ctx);\n\n                nk_layout_row_dynamic(ctx, 30, 1);\n                nk_label(ctx, \"Static immediate mode custom column layout with generated position and custom size:\", NK_TEXT_LEFT);\n                nk_layout_row_begin(ctx, NK_STATIC, 30, 3);\n                nk_layout_row_push(ctx, 100);\n                nk_button_label(ctx, \"button\");\n                nk_layout_row_push(ctx, 200);\n                nk_button_label(ctx, \"button\");\n                nk_layout_row_push(ctx, 50);\n                nk_button_label(ctx, \"button\");\n                nk_layout_row_end(ctx);\n\n                nk_layout_row_dynamic(ctx, 30, 1);\n                nk_label(ctx, \"Static free space with custom position and custom size:\", NK_TEXT_LEFT);\n                nk_layout_space_begin(ctx, NK_STATIC, 60, 4);\n                nk_layout_space_push(ctx, nk_rect(100, 0, 100, 30));\n                nk_button_label(ctx, \"button\");\n                nk_layout_space_push(ctx, nk_rect(0, 15, 100, 30));\n                nk_button_label(ctx, \"button\");\n                nk_layout_space_push(ctx, nk_rect(200, 15, 100, 30));\n                nk_button_label(ctx, \"button\");\n                nk_layout_space_push(ctx, nk_rect(100, 30, 100, 30));\n                nk_button_label(ctx, \"button\");\n                nk_layout_space_end(ctx);\n\n                nk_layout_row_dynamic(ctx, 30, 1);\n                nk_label(ctx, \"Row template:\", NK_TEXT_LEFT);\n                nk_layout_row_template_begin(ctx, 30);\n                nk_layout_row_template_push_dynamic(ctx);\n                nk_layout_row_template_push_variable(ctx, 80);\n                nk_layout_row_template_push_static(ctx, 80);\n                nk_layout_row_template_end(ctx);\n                nk_button_label(ctx, \"button\");\n                nk_button_label(ctx, \"button\");\n                nk_button_label(ctx, \"button\");\n\n                nk_tree_pop(ctx);\n            }\n\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Group\", NK_MINIMIZED))\n            {\n                static nk_bool group_titlebar = nk_false;\n                static nk_bool group_border = nk_true;\n                static nk_bool group_no_scrollbar = nk_false;\n                static int group_width = 320;\n                static int group_height = 200;\n\n                nk_flags group_flags = 0;\n                if (group_border) group_flags |= NK_WINDOW_BORDER;\n                if (group_no_scrollbar) group_flags |= NK_WINDOW_NO_SCROLLBAR;\n                if (group_titlebar) group_flags |= NK_WINDOW_TITLE;\n\n                nk_layout_row_dynamic(ctx, 30, 3);\n                nk_checkbox_label(ctx, \"Titlebar\", &group_titlebar);\n                nk_checkbox_label(ctx, \"Border\", &group_border);\n                nk_checkbox_label(ctx, \"No Scrollbar\", &group_no_scrollbar);\n\n                nk_layout_row_begin(ctx, NK_STATIC, 22, 3);\n                nk_layout_row_push(ctx, 50);\n                nk_label(ctx, \"size:\", NK_TEXT_LEFT);\n                nk_layout_row_push(ctx, 130);\n                nk_property_int(ctx, \"#Width:\", 100, &group_width, 500, 10, 1);\n                nk_layout_row_push(ctx, 130);\n                nk_property_int(ctx, \"#Height:\", 100, &group_height, 500, 10, 1);\n                nk_layout_row_end(ctx);\n\n                nk_layout_row_static(ctx, (float)group_height, group_width, 2);\n                if (nk_group_begin(ctx, \"Group\", group_flags)) {\n                    int i = 0;\n                    static nk_bool selected[16];\n                    nk_layout_row_static(ctx, 18, 100, 1);\n                    for (i = 0; i < 16; ++i)\n                        nk_selectable_label(ctx, (selected[i]) ? \"Selected\": \"Unselected\", NK_TEXT_CENTERED, &selected[i]);\n                    nk_group_end(ctx);\n                }\n                nk_tree_pop(ctx);\n            }\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Tree\", NK_MINIMIZED))\n            {\n                static nk_bool root_selected = 0;\n                nk_bool sel = root_selected;\n                if (nk_tree_element_push(ctx, NK_TREE_NODE, \"Root\", NK_MINIMIZED, &sel)) {\n                    static nk_bool selected[8];\n                    int i = 0;\n                    nk_bool node_select = selected[0];\n                    if (sel != root_selected) {\n                        root_selected = sel;\n                        for (i = 0; i < 8; ++i)\n                            selected[i] = sel;\n                    }\n                    if (nk_tree_element_push(ctx, NK_TREE_NODE, \"Node\", NK_MINIMIZED, &node_select)) {\n                        int j = 0;\n                        static nk_bool sel_nodes[4];\n                        if (node_select != selected[0]) {\n                            selected[0] = node_select;\n                            for (i = 0; i < 4; ++i)\n                                sel_nodes[i] = node_select;\n                        }\n                        nk_layout_row_static(ctx, 18, 100, 1);\n                        for (j = 0; j < 4; ++j)\n                            nk_selectable_symbol_label(ctx, NK_SYMBOL_CIRCLE_SOLID, (sel_nodes[j]) ? \"Selected\": \"Unselected\", NK_TEXT_RIGHT, &sel_nodes[j]);\n                        nk_tree_element_pop(ctx);\n                    }\n                    nk_layout_row_static(ctx, 18, 100, 1);\n                    for (i = 1; i < 8; ++i)\n                        nk_selectable_symbol_label(ctx, NK_SYMBOL_CIRCLE_SOLID, (selected[i]) ? \"Selected\": \"Unselected\", NK_TEXT_RIGHT, &selected[i]);\n                    nk_tree_element_pop(ctx);\n                }\n                nk_tree_pop(ctx);\n            }\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Notebook\", NK_MINIMIZED))\n            {\n                static int current_tab = 0;\n                float step = (2*3.141592654f) / 32;\n                enum chart_type {CHART_LINE, CHART_HISTO, CHART_MIXED};\n                const char *names[] = {\"Lines\", \"Columns\", \"Mixed\"};\n                float id = 0;\n                int i;\n\n                /* Header */\n                nk_style_push_vec2(ctx, &ctx->style.window.spacing, nk_vec2(0,0));\n                nk_style_push_float(ctx, &ctx->style.button.rounding, 0);\n                nk_layout_row_begin(ctx, NK_STATIC, 20, 3);\n                for (i = 0; i < 3; ++i) {\n                    /* make sure button perfectly fits text */\n                    const struct nk_user_font *f = ctx->style.font;\n                    float text_width = f->width(f->userdata, f->height, names[i], nk_strlen(names[i]));\n                    float widget_width = text_width + 3 * ctx->style.button.padding.x;\n                    nk_layout_row_push(ctx, widget_width);\n                    if (current_tab == i) {\n                        /* active tab gets highlighted */\n                        struct nk_style_item button_color = ctx->style.button.normal;\n                        ctx->style.button.normal = ctx->style.button.active;\n                        current_tab = nk_button_label(ctx, names[i]) ? i: current_tab;\n                        ctx->style.button.normal = button_color;\n                    } else current_tab = nk_button_label(ctx, names[i]) ? i: current_tab;\n                }\n                nk_style_pop_float(ctx);\n\n                /* Body */\n                nk_layout_row_dynamic(ctx, 140, 1);\n                if (nk_group_begin(ctx, \"Notebook\", NK_WINDOW_BORDER))\n                {\n                    nk_style_pop_vec2(ctx);\n                    switch (current_tab) {\n                    default: break;\n                    case CHART_LINE:\n                        nk_layout_row_dynamic(ctx, 100, 1);\n                        if (nk_chart_begin_colored(ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {\n                            nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f);\n                            for (i = 0, id = 0; i < 32; ++i) {\n                                nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);\n                                nk_chart_push_slot(ctx, (float)cos(id), 1);\n                                id += step;\n                            }\n                        }\n                        nk_chart_end(ctx);\n                        break;\n                    case CHART_HISTO:\n                        nk_layout_row_dynamic(ctx, 100, 1);\n                        if (nk_chart_begin_colored(ctx, NK_CHART_COLUMN, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {\n                            for (i = 0, id = 0; i < 32; ++i) {\n                                nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);\n                                id += step;\n                            }\n                        }\n                        nk_chart_end(ctx);\n                        break;\n                    case CHART_MIXED:\n                        nk_layout_row_dynamic(ctx, 100, 1);\n                        if (nk_chart_begin_colored(ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {\n                            nk_chart_add_slot_colored(ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f);\n                            nk_chart_add_slot_colored(ctx, NK_CHART_COLUMN, nk_rgb(0,255,0), nk_rgb(0,150,0), 32, 0.0f, 1.0f);\n                            for (i = 0, id = 0; i < 32; ++i) {\n                                nk_chart_push_slot(ctx, (float)fabs(sin(id)), 0);\n                                nk_chart_push_slot(ctx, (float)fabs(cos(id)), 1);\n                                nk_chart_push_slot(ctx, (float)fabs(sin(id)), 2);\n                                id += step;\n                            }\n                        }\n                        nk_chart_end(ctx);\n                        break;\n                    }\n                    nk_group_end(ctx);\n                } else nk_style_pop_vec2(ctx);\n                nk_tree_pop(ctx);\n            }\n\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Simple\", NK_MINIMIZED))\n            {\n                nk_layout_row_dynamic(ctx, 300, 2);\n                if (nk_group_begin(ctx, \"Group_Without_Border\", 0)) {\n                    int i = 0;\n                    char buffer[64];\n                    nk_layout_row_static(ctx, 18, 150, 1);\n                    for (i = 0; i < 64; ++i) {\n                        sprintf(buffer, \"0x%02x\", i);\n                        nk_labelf(ctx, NK_TEXT_LEFT, \"%s: scrollable region\", buffer);\n                    }\n                    nk_group_end(ctx);\n                }\n                if (nk_group_begin(ctx, \"Group_With_Border\", NK_WINDOW_BORDER)) {\n                    int i = 0;\n                    char buffer[64];\n                    nk_layout_row_dynamic(ctx, 25, 2);\n                    for (i = 0; i < 64; ++i) {\n                        sprintf(buffer, \"%08d\", ((((i%7)*10)^32))+(64+(i%2)*2));\n                        nk_button_label(ctx, buffer);\n                    }\n                    nk_group_end(ctx);\n                }\n                nk_tree_pop(ctx);\n            }\n\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Complex\", NK_MINIMIZED))\n            {\n                int i;\n                nk_layout_space_begin(ctx, NK_STATIC, 500, 64);\n                nk_layout_space_push(ctx, nk_rect(0,0,150,500));\n                if (nk_group_begin(ctx, \"Group_left\", NK_WINDOW_BORDER)) {\n                    static nk_bool selected[32];\n                    nk_layout_row_static(ctx, 18, 100, 1);\n                    for (i = 0; i < 32; ++i)\n                        nk_selectable_label(ctx, (selected[i]) ? \"Selected\": \"Unselected\", NK_TEXT_CENTERED, &selected[i]);\n                    nk_group_end(ctx);\n                }\n\n                nk_layout_space_push(ctx, nk_rect(160,0,150,240));\n                if (nk_group_begin(ctx, \"Group_top\", NK_WINDOW_BORDER)) {\n                    nk_layout_row_dynamic(ctx, 25, 1);\n                    nk_button_label(ctx, \"#FFAA\");\n                    nk_button_label(ctx, \"#FFBB\");\n                    nk_button_label(ctx, \"#FFCC\");\n                    nk_button_label(ctx, \"#FFDD\");\n                    nk_button_label(ctx, \"#FFEE\");\n                    nk_button_label(ctx, \"#FFFF\");\n                    nk_group_end(ctx);\n                }\n\n                nk_layout_space_push(ctx, nk_rect(160,250,150,250));\n                if (nk_group_begin(ctx, \"Group_buttom\", NK_WINDOW_BORDER)) {\n                    nk_layout_row_dynamic(ctx, 25, 1);\n                    nk_button_label(ctx, \"#FFAA\");\n                    nk_button_label(ctx, \"#FFBB\");\n                    nk_button_label(ctx, \"#FFCC\");\n                    nk_button_label(ctx, \"#FFDD\");\n                    nk_button_label(ctx, \"#FFEE\");\n                    nk_button_label(ctx, \"#FFFF\");\n                    nk_group_end(ctx);\n                }\n\n                nk_layout_space_push(ctx, nk_rect(320,0,150,150));\n                if (nk_group_begin(ctx, \"Group_right_top\", NK_WINDOW_BORDER)) {\n                    static nk_bool selected[4];\n                    nk_layout_row_static(ctx, 18, 100, 1);\n                    for (i = 0; i < 4; ++i)\n                        nk_selectable_label(ctx, (selected[i]) ? \"Selected\": \"Unselected\", NK_TEXT_CENTERED, &selected[i]);\n                    nk_group_end(ctx);\n                }\n\n                nk_layout_space_push(ctx, nk_rect(320,160,150,150));\n                if (nk_group_begin(ctx, \"Group_right_center\", NK_WINDOW_BORDER)) {\n                    static nk_bool selected[4];\n                    nk_layout_row_static(ctx, 18, 100, 1);\n                    for (i = 0; i < 4; ++i)\n                        nk_selectable_label(ctx, (selected[i]) ? \"Selected\": \"Unselected\", NK_TEXT_CENTERED, &selected[i]);\n                    nk_group_end(ctx);\n                }\n\n                nk_layout_space_push(ctx, nk_rect(320,320,150,150));\n                if (nk_group_begin(ctx, \"Group_right_bottom\", NK_WINDOW_BORDER)) {\n                    static nk_bool selected[4];\n                    nk_layout_row_static(ctx, 18, 100, 1);\n                    for (i = 0; i < 4; ++i)\n                        nk_selectable_label(ctx, (selected[i]) ? \"Selected\": \"Unselected\", NK_TEXT_CENTERED, &selected[i]);\n                    nk_group_end(ctx);\n                }\n                nk_layout_space_end(ctx);\n                nk_tree_pop(ctx);\n            }\n\n            if (nk_tree_push(ctx, NK_TREE_NODE, \"Splitter\", NK_MINIMIZED))\n            {\n                const struct nk_input *in = &ctx->input;\n                nk_layout_row_static(ctx, 20, 320, 1);\n                nk_label(ctx, \"Use slider and spinner to change tile size\", NK_TEXT_LEFT);\n                nk_label(ctx, \"Drag the space between tiles to change tile ratio\", NK_TEXT_LEFT);\n\n                if (nk_tree_push(ctx, NK_TREE_NODE, \"Vertical\", NK_MINIMIZED))\n                {\n                    static float a = 100, b = 100, c = 100;\n                    struct nk_rect bounds;\n\n                    float row_layout[5];\n                    row_layout[0] = a;\n                    row_layout[1] = 8;\n                    row_layout[2] = b;\n                    row_layout[3] = 8;\n                    row_layout[4] = c;\n\n                    /* header */\n                    nk_layout_row_static(ctx, 30, 100, 2);\n                    nk_label(ctx, \"left:\", NK_TEXT_LEFT);\n                    nk_slider_float(ctx, 10.0f, &a, 200.0f, 10.0f);\n\n                    nk_label(ctx, \"middle:\", NK_TEXT_LEFT);\n                    nk_slider_float(ctx, 10.0f, &b, 200.0f, 10.0f);\n\n                    nk_label(ctx, \"right:\", NK_TEXT_LEFT);\n                    nk_slider_float(ctx, 10.0f, &c, 200.0f, 10.0f);\n\n                    /* tiles */\n                    nk_layout_row(ctx, NK_STATIC, 200, 5, row_layout);\n\n                    /* left space */\n                    if (nk_group_begin(ctx, \"left\", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {\n                        nk_layout_row_dynamic(ctx, 25, 1);\n                        nk_button_label(ctx, \"#FFAA\");\n                        nk_button_label(ctx, \"#FFBB\");\n                        nk_button_label(ctx, \"#FFCC\");\n                        nk_button_label(ctx, \"#FFDD\");\n                        nk_button_label(ctx, \"#FFEE\");\n                        nk_button_label(ctx, \"#FFFF\");\n                        nk_group_end(ctx);\n                    }\n\n                    /* scaler */\n                    bounds = nk_widget_bounds(ctx);\n                    nk_spacing(ctx, 1);\n                    if ((nk_input_is_mouse_hovering_rect(in, bounds) ||\n                        nk_input_is_mouse_prev_hovering_rect(in, bounds)) &&\n                        nk_input_is_mouse_down(in, NK_BUTTON_LEFT))\n                    {\n                        a = row_layout[0] + in->mouse.delta.x;\n                        b = row_layout[2] - in->mouse.delta.x;\n                    }\n\n                    /* middle space */\n                    if (nk_group_begin(ctx, \"center\", NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {\n                        nk_layout_row_dynamic(ctx, 25, 1);\n                        nk_button_label(ctx, \"#FFAA\");\n                        nk_button_label(ctx, \"#FFBB\");\n                        nk_button_label(ctx, \"#FFCC\");\n                        nk_button_label(ctx, \"#FFDD\");\n                        nk_button_label(ctx, \"#FFEE\");\n                        nk_button_label(ctx, \"#FFFF\");\n                        nk_group_end(ctx);\n                    }\n\n                    /* scaler */\n                    bounds = nk_widget_bounds(ctx);\n                    nk_spacing(ctx, 1);\n                    if ((nk_input_is_mouse_hovering_rect(in, bounds) ||\n                        nk_input_is_mouse_prev_hovering_rect(in, bounds)) &&\n                        nk_input_is_mouse_down(in, NK_BUTTON_LEFT))\n                    {\n                        b = (row_layout[2] + in->mouse.delta.x);\n                        c = (row_layout[4] - in->mouse.delta.x);\n                    }\n\n                    /* right space */\n                    if (nk_group_begin(ctx, \"right\", NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {\n                        nk_layout_row_dynamic(ctx, 25, 1);\n                        nk_button_label(ctx, \"#FFAA\");\n                        nk_button_label(ctx, \"#FFBB\");\n                        nk_button_label(ctx, \"#FFCC\");\n                        nk_button_label(ctx, \"#FFDD\");\n                        nk_button_label(ctx, \"#FFEE\");\n                        nk_button_label(ctx, \"#FFFF\");\n                        nk_group_end(ctx);\n                    }\n\n                    nk_tree_pop(ctx);\n                }\n\n                if (nk_tree_push(ctx, NK_TREE_NODE, \"Horizontal\", NK_MINIMIZED))\n                {\n                    static float a = 100, b = 100, c = 100;\n                    struct nk_rect bounds;\n\n                    /* header */\n                    nk_layout_row_static(ctx, 30, 100, 2);\n                    nk_label(ctx, \"top:\", NK_TEXT_LEFT);\n                    nk_slider_float(ctx, 10.0f, &a, 200.0f, 10.0f);\n\n                    nk_label(ctx, \"middle:\", NK_TEXT_LEFT);\n                    nk_slider_float(ctx, 10.0f, &b, 200.0f, 10.0f);\n\n                    nk_label(ctx, \"bottom:\", NK_TEXT_LEFT);\n                    nk_slider_float(ctx, 10.0f, &c, 200.0f, 10.0f);\n\n                    /* top space */\n                    nk_layout_row_dynamic(ctx, a, 1);\n                    if (nk_group_begin(ctx, \"top\", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {\n                        nk_layout_row_dynamic(ctx, 25, 3);\n                        nk_button_label(ctx, \"#FFAA\");\n                        nk_button_label(ctx, \"#FFBB\");\n                        nk_button_label(ctx, \"#FFCC\");\n                        nk_button_label(ctx, \"#FFDD\");\n                        nk_button_label(ctx, \"#FFEE\");\n                        nk_button_label(ctx, \"#FFFF\");\n                        nk_group_end(ctx);\n                    }\n\n                    /* scaler */\n                    nk_layout_row_dynamic(ctx, 8, 1);\n                    bounds = nk_widget_bounds(ctx);\n                    nk_spacing(ctx, 1);\n                    if ((nk_input_is_mouse_hovering_rect(in, bounds) ||\n                        nk_input_is_mouse_prev_hovering_rect(in, bounds)) &&\n                        nk_input_is_mouse_down(in, NK_BUTTON_LEFT))\n                    {\n                        a = a + in->mouse.delta.y;\n                        b = b - in->mouse.delta.y;\n                    }\n\n                    /* middle space */\n                    nk_layout_row_dynamic(ctx, b, 1);\n                    if (nk_group_begin(ctx, \"middle\", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {\n                        nk_layout_row_dynamic(ctx, 25, 3);\n                        nk_button_label(ctx, \"#FFAA\");\n                        nk_button_label(ctx, \"#FFBB\");\n                        nk_button_label(ctx, \"#FFCC\");\n                        nk_button_label(ctx, \"#FFDD\");\n                        nk_button_label(ctx, \"#FFEE\");\n                        nk_button_label(ctx, \"#FFFF\");\n                        nk_group_end(ctx);\n                    }\n\n                    {\n                        /* scaler */\n                        nk_layout_row_dynamic(ctx, 8, 1);\n                        bounds = nk_widget_bounds(ctx);\n                        if ((nk_input_is_mouse_hovering_rect(in, bounds) ||\n                            nk_input_is_mouse_prev_hovering_rect(in, bounds)) &&\n                            nk_input_is_mouse_down(in, NK_BUTTON_LEFT))\n                        {\n                            b = b + in->mouse.delta.y;\n                            c = c - in->mouse.delta.y;\n                        }\n                    }\n\n                    /* bottom space */\n                    nk_layout_row_dynamic(ctx, c, 1);\n                    if (nk_group_begin(ctx, \"bottom\", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER)) {\n                        nk_layout_row_dynamic(ctx, 25, 3);\n                        nk_button_label(ctx, \"#FFAA\");\n                        nk_button_label(ctx, \"#FFBB\");\n                        nk_button_label(ctx, \"#FFCC\");\n                        nk_button_label(ctx, \"#FFDD\");\n                        nk_button_label(ctx, \"#FFEE\");\n                        nk_button_label(ctx, \"#FFFF\");\n                        nk_group_end(ctx);\n                    }\n                    nk_tree_pop(ctx);\n                }\n                nk_tree_pop(ctx);\n            }\n            nk_tree_pop(ctx);\n        }\n\n        /* Input */\n        if (nk_tree_push(ctx, NK_TREE_TAB, \"Input\", NK_MINIMIZED))\n        {\n            const struct nk_input *in = &ctx->input;\n            static const char *button_names[NK_BUTTON_MAX] = {\n                \"Left\", \"Middle\", \"Right\", \"Double Click\", \"X1\", \"X2\"\n            };\n            int i;\n\n            /* Mouse Buttons*/\n            nk_layout_row_dynamic(ctx, 30, 1);\n            nk_label(ctx, \"Mouse Buttons\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 20, 2);\n            for (i = 0; i < NK_BUTTON_MAX; i++) {\n                nk_label(ctx, button_names[i], NK_TEXT_LEFT);\n                if (nk_input_is_mouse_pressed(in, i))\n                    nk_label(ctx, \"Pressed\", NK_TEXT_LEFT);\n                else if (nk_input_is_mouse_down(in, i))\n                    nk_label(ctx, \"Down\", NK_TEXT_LEFT);\n                else if (nk_input_is_mouse_released(in, i))\n                    nk_label(ctx, \"Released\", NK_TEXT_LEFT);\n                else\n                    nk_label(ctx, \"Up\", NK_TEXT_LEFT);\n            }\n\n            /* Mouse Wheel */\n            nk_layout_row_dynamic(ctx, 30, 1);\n            nk_label(ctx, \"Mouse Wheel\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 20, 2);\n            nk_labelf(ctx, NK_TEXT_LEFT, \"X: %.2f\", in->mouse.scroll_delta.x);\n            nk_labelf(ctx, NK_TEXT_LEFT, \"Y: %.2f\", in->mouse.scroll_delta.y);\n            nk_tree_pop(ctx);\n        }\n\n        if (disable_widgets)\n     \t\tnk_widget_disable_end(ctx);\n    }\n    nk_end(ctx);\n    return !nk_window_is_closed(ctx, \"Overview\");\n}\n"
  },
  {
    "path": "demo/common/style.c",
    "content": "enum theme {\n  THEME_BLACK,\n  THEME_WHITE,\n  THEME_RED,\n  THEME_BLUE,\n  THEME_DARK,\n  THEME_DRACULA,\n  THEME_CATPPUCCIN_LATTE,\n  THEME_CATPPUCCIN_FRAPPE,\n  THEME_CATPPUCCIN_MACCHIATO,\n  THEME_CATPPUCCIN_MOCHA\n  \n};\n\nstatic void set_style(struct nk_context *ctx, enum theme theme) {\n  struct nk_color table[NK_COLOR_COUNT];\n  if (theme == THEME_WHITE) {\n    table[NK_COLOR_TEXT] = nk_rgba(70, 70, 70, 255);\n    table[NK_COLOR_WINDOW] = nk_rgba(175, 175, 175, 255);\n    table[NK_COLOR_HEADER] = nk_rgba(175, 175, 175, 255);\n    table[NK_COLOR_BORDER] = nk_rgba(0, 0, 0, 255);\n    table[NK_COLOR_BUTTON] = nk_rgba(185, 185, 185, 255);\n    table[NK_COLOR_BUTTON_HOVER] = nk_rgba(170, 170, 170, 255);\n    table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(160, 160, 160, 255);\n    table[NK_COLOR_TOGGLE] = nk_rgba(150, 150, 150, 255);\n    table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(120, 120, 120, 255);\n    table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(175, 175, 175, 255);\n    table[NK_COLOR_SELECT] = nk_rgba(190, 190, 190, 255);\n    table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(175, 175, 175, 255);\n    table[NK_COLOR_SLIDER] = nk_rgba(190, 190, 190, 255);\n    table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(80, 80, 80, 255);\n    table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(70, 70, 70, 255);\n    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(60, 60, 60, 255);\n    table[NK_COLOR_PROPERTY] = nk_rgba(175, 175, 175, 255);\n    table[NK_COLOR_EDIT] = nk_rgba(150, 150, 150, 255);\n    table[NK_COLOR_EDIT_CURSOR] = nk_rgba(0, 0, 0, 255);\n    table[NK_COLOR_COMBO] = nk_rgba(175, 175, 175, 255);\n    table[NK_COLOR_CHART] = nk_rgba(160, 160, 160, 255);\n    table[NK_COLOR_CHART_COLOR] = nk_rgba(45, 45, 45, 255);\n    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255);\n    table[NK_COLOR_SCROLLBAR] = nk_rgba(180, 180, 180, 255);\n    table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(140, 140, 140, 255);\n    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(150, 150, 150, 255);\n    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(160, 160, 160, 255);\n    table[NK_COLOR_TAB_HEADER] = nk_rgba(180, 180, 180, 255);\n    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];\n    table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];\n    table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];\n    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];\n    nk_style_from_table(ctx, table);\n  } else if (theme == THEME_RED) {\n    table[NK_COLOR_TEXT] = nk_rgba(190, 190, 190, 255);\n    table[NK_COLOR_WINDOW] = nk_rgba(30, 33, 40, 215);\n    table[NK_COLOR_HEADER] = nk_rgba(181, 45, 69, 220);\n    table[NK_COLOR_BORDER] = nk_rgba(51, 55, 67, 255);\n    table[NK_COLOR_BUTTON] = nk_rgba(181, 45, 69, 255);\n    table[NK_COLOR_BUTTON_HOVER] = nk_rgba(190, 50, 70, 255);\n    table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(195, 55, 75, 255);\n    table[NK_COLOR_TOGGLE] = nk_rgba(51, 55, 67, 255);\n    table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 60, 60, 255);\n    table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(181, 45, 69, 255);\n    table[NK_COLOR_SELECT] = nk_rgba(51, 55, 67, 255);\n    table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(181, 45, 69, 255);\n    table[NK_COLOR_SLIDER] = nk_rgba(51, 55, 67, 255);\n    table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(181, 45, 69, 255);\n    table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(186, 50, 74, 255);\n    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(191, 55, 79, 255);\n    table[NK_COLOR_PROPERTY] = nk_rgba(51, 55, 67, 255);\n    table[NK_COLOR_EDIT] = nk_rgba(51, 55, 67, 225);\n    table[NK_COLOR_EDIT_CURSOR] = nk_rgba(190, 190, 190, 255);\n    table[NK_COLOR_COMBO] = nk_rgba(51, 55, 67, 255);\n    table[NK_COLOR_CHART] = nk_rgba(51, 55, 67, 255);\n    table[NK_COLOR_CHART_COLOR] = nk_rgba(170, 40, 60, 255);\n    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255);\n    table[NK_COLOR_SCROLLBAR] = nk_rgba(30, 33, 40, 255);\n    table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(64, 84, 95, 255);\n    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(70, 90, 100, 255);\n    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(75, 95, 105, 255);\n    table[NK_COLOR_TAB_HEADER] = nk_rgba(181, 45, 69, 220);\n    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];\n    table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];\n    table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];\n    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];\n    nk_style_from_table(ctx, table);\n  } else if (theme == THEME_BLUE) {\n    table[NK_COLOR_TEXT] = nk_rgba(20, 20, 20, 255);\n    table[NK_COLOR_WINDOW] = nk_rgba(202, 212, 214, 215);\n    table[NK_COLOR_HEADER] = nk_rgba(137, 182, 224, 220);\n    table[NK_COLOR_BORDER] = nk_rgba(140, 159, 173, 255);\n    table[NK_COLOR_BUTTON] = nk_rgba(137, 182, 224, 255);\n    table[NK_COLOR_BUTTON_HOVER] = nk_rgba(142, 187, 229, 255);\n    table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(147, 192, 234, 255);\n    table[NK_COLOR_TOGGLE] = nk_rgba(177, 210, 210, 255);\n    table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(182, 215, 215, 255);\n    table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(137, 182, 224, 255);\n    table[NK_COLOR_SELECT] = nk_rgba(177, 210, 210, 255);\n    table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(137, 182, 224, 255);\n    table[NK_COLOR_SLIDER] = nk_rgba(177, 210, 210, 255);\n    table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(137, 182, 224, 245);\n    table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(142, 188, 229, 255);\n    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(147, 193, 234, 255);\n    table[NK_COLOR_PROPERTY] = nk_rgba(210, 210, 210, 255);\n    table[NK_COLOR_EDIT] = nk_rgba(210, 210, 210, 225);\n    table[NK_COLOR_EDIT_CURSOR] = nk_rgba(20, 20, 20, 255);\n    table[NK_COLOR_COMBO] = nk_rgba(210, 210, 210, 255);\n    table[NK_COLOR_CHART] = nk_rgba(210, 210, 210, 255);\n    table[NK_COLOR_CHART_COLOR] = nk_rgba(137, 182, 224, 255);\n    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255);\n    table[NK_COLOR_SCROLLBAR] = nk_rgba(190, 200, 200, 255);\n    table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(64, 84, 95, 255);\n    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(70, 90, 100, 255);\n    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(75, 95, 105, 255);\n    table[NK_COLOR_TAB_HEADER] = nk_rgba(156, 193, 220, 255);\n    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];\n    table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];\n    table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];\n    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];\n    nk_style_from_table(ctx, table);\n  } else if (theme == THEME_DARK) {\n    table[NK_COLOR_TEXT] = nk_rgba(210, 210, 210, 255);\n    table[NK_COLOR_WINDOW] = nk_rgba(57, 67, 71, 215);\n    table[NK_COLOR_HEADER] = nk_rgba(51, 51, 56, 220);\n    table[NK_COLOR_BORDER] = nk_rgba(46, 46, 46, 255);\n    table[NK_COLOR_BUTTON] = nk_rgba(48, 83, 111, 255);\n    table[NK_COLOR_BUTTON_HOVER] = nk_rgba(58, 93, 121, 255);\n    table[NK_COLOR_BUTTON_ACTIVE] = nk_rgba(63, 98, 126, 255);\n    table[NK_COLOR_TOGGLE] = nk_rgba(50, 58, 61, 255);\n    table[NK_COLOR_TOGGLE_HOVER] = nk_rgba(45, 53, 56, 255);\n    table[NK_COLOR_TOGGLE_CURSOR] = nk_rgba(48, 83, 111, 255);\n    table[NK_COLOR_SELECT] = nk_rgba(57, 67, 61, 255);\n    table[NK_COLOR_SELECT_ACTIVE] = nk_rgba(48, 83, 111, 255);\n    table[NK_COLOR_SLIDER] = nk_rgba(50, 58, 61, 255);\n    table[NK_COLOR_SLIDER_CURSOR] = nk_rgba(48, 83, 111, 245);\n    table[NK_COLOR_SLIDER_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255);\n    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255);\n    table[NK_COLOR_PROPERTY] = nk_rgba(50, 58, 61, 255);\n    table[NK_COLOR_EDIT] = nk_rgba(50, 58, 61, 225);\n    table[NK_COLOR_EDIT_CURSOR] = nk_rgba(210, 210, 210, 255);\n    table[NK_COLOR_COMBO] = nk_rgba(50, 58, 61, 255);\n    table[NK_COLOR_CHART] = nk_rgba(50, 58, 61, 255);\n    table[NK_COLOR_CHART_COLOR] = nk_rgba(48, 83, 111, 255);\n    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = nk_rgba(255, 0, 0, 255);\n    table[NK_COLOR_SCROLLBAR] = nk_rgba(50, 58, 61, 255);\n    table[NK_COLOR_SCROLLBAR_CURSOR] = nk_rgba(48, 83, 111, 255);\n    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = nk_rgba(53, 88, 116, 255);\n    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = nk_rgba(58, 93, 121, 255);\n    table[NK_COLOR_TAB_HEADER] = nk_rgba(48, 83, 111, 255);\n    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];\n    table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];\n    table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];\n    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];\n    nk_style_from_table(ctx, table);\n  } else if (theme == THEME_DRACULA) {\n    struct nk_color background = nk_rgba(40, 42, 54, 255);\n    struct nk_color currentline = nk_rgba(68, 71, 90, 255);\n    struct nk_color foreground = nk_rgba(248, 248, 242, 255);\n    struct nk_color comment = nk_rgba(98, 114, 164, 255);\n    /* struct nk_color cyan = nk_rgba(139, 233, 253, 255); */\n    /* struct nk_color green = nk_rgba(80, 250, 123, 255); */\n    /* struct nk_color orange = nk_rgba(255, 184, 108, 255); */\n    struct nk_color pink = nk_rgba(255, 121, 198, 255);\n    struct nk_color purple = nk_rgba(189, 147, 249, 255);\n    /* struct nk_color red = nk_rgba(255, 85, 85, 255); */\n    /* struct nk_color yellow = nk_rgba(241, 250, 140, 255); */\n    table[NK_COLOR_TEXT] = foreground;\n    table[NK_COLOR_WINDOW] = background;\n    table[NK_COLOR_HEADER] = currentline;\n    table[NK_COLOR_BORDER] = currentline;\n    table[NK_COLOR_BUTTON] = currentline;\n    table[NK_COLOR_BUTTON_HOVER] = comment;\n    table[NK_COLOR_BUTTON_ACTIVE] = purple;\n    table[NK_COLOR_TOGGLE] = currentline;\n    table[NK_COLOR_TOGGLE_HOVER] = comment;\n    table[NK_COLOR_TOGGLE_CURSOR] = pink;\n    table[NK_COLOR_SELECT] = currentline;\n    table[NK_COLOR_SELECT_ACTIVE] = comment;\n    table[NK_COLOR_SLIDER] = background;\n    table[NK_COLOR_SLIDER_CURSOR] = currentline;\n    table[NK_COLOR_SLIDER_CURSOR_HOVER] = comment;\n    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = comment;\n    table[NK_COLOR_PROPERTY] = currentline;\n    table[NK_COLOR_EDIT] = currentline;\n    table[NK_COLOR_EDIT_CURSOR] = foreground;\n    table[NK_COLOR_COMBO] = currentline;\n    table[NK_COLOR_CHART] = currentline;\n    table[NK_COLOR_CHART_COLOR] = comment;\n    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = purple;\n    table[NK_COLOR_SCROLLBAR] = background;\n    table[NK_COLOR_SCROLLBAR_CURSOR] = currentline;\n    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = comment;\n    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = purple;\n    table[NK_COLOR_TAB_HEADER] = currentline;\n    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];\n    table[NK_COLOR_KNOB_CURSOR] = table[NK_COLOR_SLIDER_CURSOR];\n    table[NK_COLOR_KNOB_CURSOR_HOVER] = table[NK_COLOR_SLIDER_CURSOR_HOVER];\n    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = table[NK_COLOR_SLIDER_CURSOR_ACTIVE];\n    nk_style_from_table(ctx, table);\n  } else if (theme == THEME_CATPPUCCIN_LATTE) {\n    /*struct nk_color rosewater = nk_rgba(220, 138, 120, 255);*/\n    /*struct nk_color flamingo = nk_rgba(221, 120, 120, 255);*/\n    struct nk_color pink = nk_rgba(234, 118, 203, 255);\n    struct nk_color mauve = nk_rgba(136, 57, 239, 255);\n    /*struct nk_color red = nk_rgba(210, 15, 57, 255);*/\n    /*struct nk_color maroon = nk_rgba(230, 69, 83, 255);*/\n    /*struct nk_color peach = nk_rgba(254, 100, 11, 255);*/\n    struct nk_color yellow = nk_rgba(223, 142, 29, 255);\n    /*struct nk_color green = nk_rgba(64, 160, 43, 255);*/\n    struct nk_color teal = nk_rgba(23, 146, 153, 255);\n    /*struct nk_color sky = nk_rgba(4, 165, 229, 255);*/\n    /*struct nk_color sapphire = nk_rgba(32, 159, 181, 255);*/\n    /*struct nk_color blue = nk_rgba(30, 102, 245, 255);*/\n    /*struct nk_color lavender = nk_rgba(114, 135, 253, 255);*/\n    struct nk_color text = nk_rgba(76, 79, 105, 255);\n    /*struct nk_color subtext1 = nk_rgba(92, 95, 119, 255);*/\n    /*struct nk_color subtext0 = nk_rgba(108, 111, 133, 255);*/\n    struct nk_color overlay2 = nk_rgba(124, 127, 147, 55);\n    /*struct nk_color overlay1 = nk_rgba(140, 143, 161, 255);*/\n    struct nk_color overlay0 = nk_rgba(156, 160, 176, 255);\n    struct nk_color surface2 = nk_rgba(172, 176, 190, 255);\n    struct nk_color surface1 = nk_rgba(188, 192, 204, 255);\n    struct nk_color surface0 = nk_rgba(204, 208, 218, 255);\n    struct nk_color base = nk_rgba(239, 241, 245, 255);\n    struct nk_color mantle = nk_rgba(230, 233, 239, 255);\n    /*struct nk_color crust = nk_rgba(220, 224, 232, 255);*/\n    table[NK_COLOR_TEXT] = text;\n    table[NK_COLOR_WINDOW] = base;\n    table[NK_COLOR_HEADER] = mantle;\n    table[NK_COLOR_BORDER] = mantle;\n    table[NK_COLOR_BUTTON] = surface0;\n    table[NK_COLOR_BUTTON_HOVER] = overlay2;\n    table[NK_COLOR_BUTTON_ACTIVE] = overlay0;\n    table[NK_COLOR_TOGGLE] = surface2;\n    table[NK_COLOR_TOGGLE_HOVER] = overlay2;\n    table[NK_COLOR_TOGGLE_CURSOR] = yellow;\n    table[NK_COLOR_SELECT] = surface0;\n    table[NK_COLOR_SELECT_ACTIVE] = overlay0;\n    table[NK_COLOR_SLIDER] = surface1;\n    table[NK_COLOR_SLIDER_CURSOR] = teal;\n    table[NK_COLOR_SLIDER_CURSOR_HOVER] = teal;\n    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = teal;\n    table[NK_COLOR_PROPERTY] = surface0;\n    table[NK_COLOR_EDIT] = surface0;\n    table[NK_COLOR_EDIT_CURSOR] = mauve;\n    table[NK_COLOR_COMBO] = surface0;\n    table[NK_COLOR_CHART] = surface0;\n    table[NK_COLOR_CHART_COLOR] = teal;\n    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = mauve;\n    table[NK_COLOR_SCROLLBAR] = surface0;\n    table[NK_COLOR_SCROLLBAR_CURSOR] = overlay0;\n    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = mauve;\n    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = mauve;\n    table[NK_COLOR_TAB_HEADER] = surface0;\n    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];\n    table[NK_COLOR_KNOB_CURSOR] = pink;\n    table[NK_COLOR_KNOB_CURSOR_HOVER] = pink;\n    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = pink;\n    nk_style_from_table(ctx, table);\n  } else if (theme == THEME_CATPPUCCIN_FRAPPE) {\n    /*struct nk_color rosewater = nk_rgba(242, 213, 207, 255);*/\n    /*struct nk_color flamingo = nk_rgba(238, 190, 190, 255);*/\n    struct nk_color pink = nk_rgba(244, 184, 228, 255);\n    /*struct nk_color mauve = nk_rgba(202, 158, 230, 255);*/\n    /*struct nk_color red = nk_rgba(231, 130, 132, 255);*/\n    /*struct nk_color maroon = nk_rgba(234, 153, 156, 255);*/\n    /*struct nk_color peach = nk_rgba(239, 159, 118, 255);*/\n    /*struct nk_color yellow = nk_rgba(229, 200, 144, 255);*/\n    struct nk_color green = nk_rgba(166, 209, 137, 255);\n    /*struct nk_color teal = nk_rgba(129, 200, 190, 255);*/\n    /*struct nk_color sky = nk_rgba(153, 209, 219, 255);*/\n    /*struct nk_color sapphire = nk_rgba(133, 193, 220, 255);*/\n    /*struct nk_color blue = nk_rgba(140, 170, 238, 255);*/\n    struct nk_color lavender = nk_rgba(186, 187, 241, 255);\n    struct nk_color text = nk_rgba(198, 208, 245, 255);\n    /*struct nk_color subtext1 = nk_rgba(181, 191, 226, 255);*/\n    /*struct nk_color subtext0 = nk_rgba(165, 173, 206, 255);*/\n    struct nk_color overlay2 = nk_rgba(148, 156, 187, 255);\n    struct nk_color overlay1 = nk_rgba(131, 139, 167, 255);\n    struct nk_color overlay0 = nk_rgba(115, 121, 148, 255);\n    struct nk_color surface2 = nk_rgba(98, 104, 128, 255);\n    struct nk_color surface1 = nk_rgba(81, 87, 109, 255);\n    struct nk_color surface0 = nk_rgba(65, 69, 89, 255);\n    struct nk_color base = nk_rgba(48, 52, 70, 255);\n    struct nk_color mantle = nk_rgba(41, 44, 60, 255);\n    /*struct nk_color crust = nk_rgba(35, 38, 52, 255);*/\n    table[NK_COLOR_TEXT] = text;\n    table[NK_COLOR_WINDOW] = base;\n    table[NK_COLOR_HEADER] = mantle;\n    table[NK_COLOR_BORDER] = mantle;\n    table[NK_COLOR_BUTTON] = surface0;\n    table[NK_COLOR_BUTTON_HOVER] = overlay1;\n    table[NK_COLOR_BUTTON_ACTIVE] = overlay0;\n    table[NK_COLOR_TOGGLE] = surface2;\n    table[NK_COLOR_TOGGLE_HOVER] = overlay2;\n    table[NK_COLOR_TOGGLE_CURSOR] = pink;\n    table[NK_COLOR_SELECT] = surface0;\n    table[NK_COLOR_SELECT_ACTIVE] = overlay0;\n    table[NK_COLOR_SLIDER] = surface1;\n    table[NK_COLOR_SLIDER_CURSOR] = green;\n    table[NK_COLOR_SLIDER_CURSOR_HOVER] = green;\n    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = green;\n    table[NK_COLOR_PROPERTY] = surface0;\n    table[NK_COLOR_EDIT] = surface0;\n    table[NK_COLOR_EDIT_CURSOR] = pink;\n    table[NK_COLOR_COMBO] = surface0;\n    table[NK_COLOR_CHART] = surface0;\n    table[NK_COLOR_CHART_COLOR] = lavender;\n    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = pink;\n    table[NK_COLOR_SCROLLBAR] = surface0;\n    table[NK_COLOR_SCROLLBAR_CURSOR] = overlay0;\n    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = lavender;\n    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = lavender;\n    table[NK_COLOR_TAB_HEADER] = surface0;\n    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];\n    table[NK_COLOR_KNOB_CURSOR] = pink;\n    table[NK_COLOR_KNOB_CURSOR_HOVER] = pink;\n    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = pink;\n    nk_style_from_table(ctx, table);\n  } else if (theme == THEME_CATPPUCCIN_MACCHIATO) {\n    /*struct nk_color rosewater = nk_rgba(244, 219, 214, 255);*/\n    /*struct nk_color flamingo = nk_rgba(240, 198, 198, 255);*/\n    struct nk_color pink = nk_rgba(245, 189, 230, 255);\n    /*struct nk_color mauve = nk_rgba(198, 160, 246, 255);*/\n    /*struct nk_color red = nk_rgba(237, 135, 150, 255);*/\n    /*struct nk_color maroon = nk_rgba(238, 153, 160, 255);*/\n    /*struct nk_color peach = nk_rgba(245, 169, 127, 255);*/\n    struct nk_color yellow = nk_rgba(238, 212, 159, 255);\n    struct nk_color green = nk_rgba(166, 218, 149, 255);\n    /*struct nk_color teal = nk_rgba(139, 213, 202, 255);*/\n    /*struct nk_color sky = nk_rgba(145, 215, 227, 255);*/\n    /*struct nk_color sapphire = nk_rgba(125, 196, 228, 255);*/\n    /*struct nk_color blue = nk_rgba(138, 173, 244, 255);*/\n    struct nk_color lavender = nk_rgba(183, 189, 248, 255);\n    struct nk_color text = nk_rgba(202, 211, 245, 255);\n    /*struct nk_color subtext1 = nk_rgba(184, 192, 224, 255);*/\n    /*struct nk_color subtext0 = nk_rgba(165, 173, 203, 255);*/\n    struct nk_color overlay2 = nk_rgba(147, 154, 183, 255);\n    struct nk_color overlay1 = nk_rgba(128, 135, 162, 255);\n    struct nk_color overlay0 = nk_rgba(110, 115, 141, 255);\n    struct nk_color surface2 = nk_rgba(91, 96, 120, 255);\n    struct nk_color surface1 = nk_rgba(73, 77, 100, 255);\n    struct nk_color surface0 = nk_rgba(54, 58, 79, 255);\n    struct nk_color base = nk_rgba(36, 39, 58, 255);\n    struct nk_color mantle = nk_rgba(30, 32, 48, 255);\n    /*struct nk_color crust = nk_rgba(24, 25, 38, 255);*/\n    table[NK_COLOR_TEXT] = text;\n    table[NK_COLOR_WINDOW] = base;\n    table[NK_COLOR_HEADER] = mantle;\n    table[NK_COLOR_BORDER] = mantle;\n    table[NK_COLOR_BUTTON] = surface0;\n    table[NK_COLOR_BUTTON_HOVER] = overlay1;\n    table[NK_COLOR_BUTTON_ACTIVE] = overlay0;\n    table[NK_COLOR_TOGGLE] = surface2;\n    table[NK_COLOR_TOGGLE_HOVER] = overlay2;\n    table[NK_COLOR_TOGGLE_CURSOR] = yellow;\n    table[NK_COLOR_SELECT] = surface0;\n    table[NK_COLOR_SELECT_ACTIVE] = overlay0;\n    table[NK_COLOR_SLIDER] = surface1;\n    table[NK_COLOR_SLIDER_CURSOR] = green;\n    table[NK_COLOR_SLIDER_CURSOR_HOVER] = green;\n    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = green;\n    table[NK_COLOR_PROPERTY] = surface0;\n    table[NK_COLOR_EDIT] = surface0;\n    table[NK_COLOR_EDIT_CURSOR] = pink;\n    table[NK_COLOR_COMBO] = surface0;\n    table[NK_COLOR_CHART] = surface0;\n    table[NK_COLOR_CHART_COLOR] = lavender;\n    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = yellow;\n    table[NK_COLOR_SCROLLBAR] = surface0;\n    table[NK_COLOR_SCROLLBAR_CURSOR] = overlay0;\n    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = lavender;\n    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = lavender;\n    table[NK_COLOR_TAB_HEADER] = surface0;\n    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];\n    table[NK_COLOR_KNOB_CURSOR] = pink;\n    table[NK_COLOR_KNOB_CURSOR_HOVER] = pink;\n    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = pink;\n    nk_style_from_table(ctx, table); \n  } else if (theme == THEME_CATPPUCCIN_MOCHA) {\n    /*struct nk_color rosewater = nk_rgba(245, 224, 220, 255);*/\n    /*struct nk_color flamingo = nk_rgba(242, 205, 205, 255);*/\n    struct nk_color pink = nk_rgba(245, 194, 231, 255);\n    /*struct nk_color mauve = nk_rgba(203, 166, 247, 255);*/\n    /*struct nk_color red = nk_rgba(243, 139, 168, 255);*/\n    /*struct nk_color maroon = nk_rgba(235, 160, 172, 255);*/\n    /*struct nk_color peach = nk_rgba(250, 179, 135, 255);*/\n    /*struct nk_color yellow = nk_rgba(249, 226, 175, 255);*/\n    struct nk_color green = nk_rgba(166, 227, 161, 255);\n    /*struct nk_color teal = nk_rgba(148, 226, 213, 255);*/\n    /*struct nk_color sky = nk_rgba(137, 220, 235, 255);*/\n    /*struct nk_color sapphire = nk_rgba(116, 199, 236, 255);*/\n    /*struct nk_color blue = nk_rgba(137, 180, 250, 255);*/\n    struct nk_color lavender = nk_rgba(180, 190, 254, 255);\n    struct nk_color text = nk_rgba(205, 214, 244, 255);\n    /*struct nk_color subtext1 = nk_rgba(186, 194, 222, 255);*/\n    /*struct nk_color subtext0 = nk_rgba(166, 173, 200, 255);*/\n    struct nk_color overlay2 = nk_rgba(147, 153, 178, 255);\n    struct nk_color overlay1 = nk_rgba(127, 132, 156, 255);\n    struct nk_color overlay0 = nk_rgba(108, 112, 134, 255);\n    struct nk_color surface2 = nk_rgba(88, 91, 112, 255);\n    struct nk_color surface1 = nk_rgba(69, 71, 90, 255);\n    struct nk_color surface0 = nk_rgba(49, 50, 68, 255);\n    struct nk_color base = nk_rgba(30, 30, 46, 255);\n    struct nk_color mantle = nk_rgba(24, 24, 37, 255);\n    /*struct nk_color crust = nk_rgba(17, 17, 27, 255);*/\n    table[NK_COLOR_TEXT] = text;\n    table[NK_COLOR_WINDOW] = base;\n    table[NK_COLOR_HEADER] = mantle;\n    table[NK_COLOR_BORDER] = mantle;\n    table[NK_COLOR_BUTTON] = surface0;\n    table[NK_COLOR_BUTTON_HOVER] = overlay1;\n    table[NK_COLOR_BUTTON_ACTIVE] = overlay0;\n    table[NK_COLOR_TOGGLE] = surface2;\n    table[NK_COLOR_TOGGLE_HOVER] = overlay2;\n    table[NK_COLOR_TOGGLE_CURSOR] = lavender;\n    table[NK_COLOR_SELECT] = surface0;\n    table[NK_COLOR_SELECT_ACTIVE] = overlay0;\n    table[NK_COLOR_SLIDER] = surface1;\n    table[NK_COLOR_SLIDER_CURSOR] = green;\n    table[NK_COLOR_SLIDER_CURSOR_HOVER] = green;\n    table[NK_COLOR_SLIDER_CURSOR_ACTIVE] = green;\n    table[NK_COLOR_PROPERTY] = surface0;\n    table[NK_COLOR_EDIT] = surface0;\n    table[NK_COLOR_EDIT_CURSOR] = lavender;\n    table[NK_COLOR_COMBO] = surface0;\n    table[NK_COLOR_CHART] = surface0;\n    table[NK_COLOR_CHART_COLOR] = lavender;\n    table[NK_COLOR_CHART_COLOR_HIGHLIGHT] = pink;\n    table[NK_COLOR_SCROLLBAR] = surface0;\n    table[NK_COLOR_SCROLLBAR_CURSOR] = overlay0;\n    table[NK_COLOR_SCROLLBAR_CURSOR_HOVER] = lavender;\n    table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE] = pink;\n    table[NK_COLOR_TAB_HEADER] = surface0;\n    table[NK_COLOR_KNOB] = table[NK_COLOR_SLIDER];\n    table[NK_COLOR_KNOB_CURSOR] = pink;\n    table[NK_COLOR_KNOB_CURSOR_HOVER] = pink;\n    table[NK_COLOR_KNOB_CURSOR_ACTIVE] = pink;\n    nk_style_from_table(ctx, table);   \n  } else {\n    nk_style_default(ctx);\n  }\n}\n"
  },
  {
    "path": "demo/common/style_configurator.c",
    "content": "\n/*\n TODO design decisions\n plural or not?  ie style_button or style_buttons?\n use the duplicate array method, or just let the user\n manually set those after calling the function by accessing ctx->style->*?\n*/\n\nstatic const char* symbols[NK_SYMBOL_MAX] =\n{\n    \"NONE\",\n    \"X\",\n    \"UNDERSCORE\",\n    \"CIRCLE_SOLID\",\n    \"CIRCLE_OUTLINE\",\n    \"RECT_SOLID\",\n    \"RECT_OUTLINE\",\n    \"TRIANGLE_UP\",\n    \"TRIANGLE_DOWN\",\n    \"TRIANGLE_LEFT\",\n    \"TRIANGLE_RIGHT\",\n    \"PLUS\",\n    \"MINUS\"\n};\n\nstatic int\nstyle_rgb(struct nk_context* ctx, const char* name, struct nk_color* color)\n{\n\tstruct nk_colorf colorf;\n\tnk_label(ctx, name, NK_TEXT_LEFT);\n\tif (nk_combo_begin_color(ctx, *color, nk_vec2(nk_widget_width(ctx), 400))) {\n\t\tnk_layout_row_dynamic(ctx, 120, 1);\n\t\tcolorf = nk_color_picker(ctx, nk_color_cf(*color), NK_RGB);\n\t\tnk_layout_row_dynamic(ctx, 25, 1);\n\t\tcolorf.r = nk_propertyf(ctx, \"#R:\", 0, colorf.r, 1.0f, 0.01f,0.005f);\n\t\tcolorf.g = nk_propertyf(ctx, \"#G:\", 0, colorf.g, 1.0f, 0.01f,0.005f);\n\t\tcolorf.b = nk_propertyf(ctx, \"#B:\", 0, colorf.b, 1.0f, 0.01f,0.005f);\n\n\t\t*color = nk_rgb_cf(colorf);\n\n\t\tnk_combo_end(ctx);\n\t\treturn 1;\n\t}\n\treturn 0;\n}\n\n/* TODO style_style_item?  how to handle images if at all? */\nstatic void\nstyle_item_color(struct nk_context* ctx, const char* name, struct nk_style_item* item)\n{\n\tstyle_rgb(ctx, name, &item->data.color);\n}\n\nstatic void\nstyle_vec2(struct nk_context* ctx, const char* name, struct nk_vec2* vec)\n{\n\tchar buffer[64];\n\tnk_label(ctx, name, NK_TEXT_LEFT);\n\tsprintf(buffer, \"%.2f, %.2f\", vec->x, vec->y);\n\tif (nk_combo_begin_label(ctx, buffer, nk_vec2(200,200))) {\n\t\tnk_layout_row_dynamic(ctx, 25, 1);\n\t\tnk_property_float(ctx, \"#X:\", -100.0f, &vec->x, 100.0f, 1,0.5f);\n\t\tnk_property_float(ctx, \"#Y:\", -100.0f, &vec->y, 100.0f, 1,0.5f);\n\t\tnk_combo_end(ctx);\n\t}\n}\n\n/* style_general? pass array in instead of static? */\nstatic void\nstyle_global_colors(struct nk_context* ctx, struct nk_color color_table[NK_COLOR_COUNT])\n{\n\tconst char* color_labels[NK_COLOR_COUNT] =\n\t{\n\t\t\"COLOR_TEXT:\",\n\t\t\"COLOR_WINDOW:\",\n\t\t\"COLOR_HEADER:\",\n\t\t\"COLOR_BORDER:\",\n\t\t\"COLOR_BUTTON:\",\n\t\t\"COLOR_BUTTON_HOVER:\",\n\t\t\"COLOR_BUTTON_ACTIVE:\",\n\t\t\"COLOR_TOGGLE:\",\n\t\t\"COLOR_TOGGLE_HOVER:\",\n\t\t\"COLOR_TOGGLE_CURSOR:\",\n\t\t\"COLOR_SELECT:\",\n\t\t\"COLOR_SELECT_ACTIVE:\",\n\t\t\"COLOR_SLIDER:\",\n\t\t\"COLOR_SLIDER_CURSOR:\",\n\t\t\"COLOR_SLIDER_CURSOR_HOVER:\",\n\t\t\"COLOR_SLIDER_CURSOR_ACTIVE:\",\n\t\t\"COLOR_PROPERTY:\",\n\t\t\"COLOR_EDIT:\",\n\t\t\"COLOR_EDIT_CURSOR:\",\n\t\t\"COLOR_COMBO:\",\n\t\t\"COLOR_CHART:\",\n\t\t\"COLOR_CHART_COLOR:\",\n\t\t\"COLOR_CHART_COLOR_HIGHLIGHT:\",\n\t\t\"COLOR_SCROLLBAR:\",\n\t\t\"COLOR_SCROLLBAR_CURSOR:\",\n\t\t\"COLOR_SCROLLBAR_CURSOR_HOVER:\",\n\t\t\"COLOR_SCROLLBAR_CURSOR_ACTIVE:\",\n\t\t\"COLOR_TAB_HEADER:\",\n\t\t\"COLOR_KNOB:\",\n\t\t\"COLOR_KNOB_CURSOR:\",\n\t\t\"COLOR_KNOB_CURSOR_HOVER:\",\n\t\t\"COLOR_KNOB_CURSOR_ACTIVE:\"\n\t};\n\n\tint clicked = 0;\n\tint i;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\tfor (i=0; i<NK_COLOR_COUNT; ++i) {\n\t\tclicked |= style_rgb(ctx, color_labels[i], &color_table[i]);\n\t}\n\n\tif (clicked) {\n\t\tnk_style_from_table(ctx, color_table);\n\t}\n}\n\nstatic void\nstyle_text(struct nk_context* ctx, struct nk_style_text* out_style)\n{\n\tstruct nk_style_text text = *out_style;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\tstyle_rgb(ctx, \"Color:\", &text.color);\n\n\tstyle_vec2(ctx, \"Padding:\", &text.padding);\n\n\t*out_style = text;\n}\n\nstatic void\nstyle_button(struct nk_context* ctx, struct nk_style_button* out_style, struct nk_style_button** duplicate_styles, int n_dups)\n{\n\tstruct nk_style_button button = *out_style;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\tstyle_item_color(ctx, \"Normal:\", &button.normal);\n\tstyle_item_color(ctx, \"Hover:\", &button.hover);\n\tstyle_item_color(ctx, \"Active:\", &button.active);\n\n\tstyle_rgb(ctx, \"Border:\", &button.border_color);\n\tstyle_rgb(ctx, \"Text Background:\", &button.text_background);\n\tstyle_rgb(ctx, \"Text Normal:\", &button.text_normal);\n\tstyle_rgb(ctx, \"Text Hover:\", &button.text_hover);\n\tstyle_rgb(ctx, \"Text Active:\", &button.text_active);\n\n\tstyle_vec2(ctx, \"Padding:\", &button.padding);\n\tstyle_vec2(ctx, \"Image Padding:\", &button.image_padding);\n\tstyle_vec2(ctx, \"Touch Padding:\", &button.touch_padding);\n\n\t{\n\tconst char* alignments[] =\n{\n\t\"LEFT\",\n\t\"CENTERED\",\n\t\"RIGHT\",\n\t\"TOP LEFT\",\n\t\"TOP CENTERED\",\n\t\"TOP_RIGHT\",\n\t\"BOTTOM LEFT\",\n\t\"BOTTOM CENTERED\",\n\t\"BOTTOM RIGHT\"\n};\n\n#define TOP_LEFT       NK_TEXT_ALIGN_TOP|NK_TEXT_ALIGN_LEFT\n#define TOP_CENTER     NK_TEXT_ALIGN_TOP|NK_TEXT_ALIGN_CENTERED\n#define TOP_RIGHT      NK_TEXT_ALIGN_TOP|NK_TEXT_ALIGN_RIGHT\n#define BOTTOM_LEFT    NK_TEXT_ALIGN_BOTTOM|NK_TEXT_ALIGN_LEFT\n#define BOTTOM_CENTER  NK_TEXT_ALIGN_BOTTOM|NK_TEXT_ALIGN_CENTERED\n#define BOTTOM_RIGHT   NK_TEXT_ALIGN_BOTTOM|NK_TEXT_ALIGN_RIGHT\n\n\tunsigned int aligns[] =\n{\n\tNK_TEXT_LEFT,\n\tNK_TEXT_CENTERED,\n\tNK_TEXT_RIGHT,\n\tTOP_LEFT,\n\tTOP_CENTER,\n\tTOP_RIGHT,\n\tBOTTOM_LEFT,\n\tBOTTOM_CENTER,\n\tBOTTOM_RIGHT\n};\n\n\tint cur_align = button.text_alignment-NK_TEXT_LEFT;\n\tint i;\n\tfor (i=0; i<(int)NK_LEN(aligns); ++i) {\n\t\tif (button.text_alignment == aligns[i]) {\n\t\t\tcur_align = i;\n\t\t\tbreak;\n\t\t}\n\t}\n\tnk_label(ctx, \"Text Alignment:\", NK_TEXT_LEFT);\n\tcur_align = nk_combo(ctx, alignments, NK_LEN(alignments), cur_align, 25, nk_vec2(200,200));\n\tbutton.text_alignment = aligns[cur_align];\n\n\tnk_property_float(ctx, \"#Border:\", -100.0f, &button.border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Rounding:\", -100.0f, &button.rounding, 100.0f, 1,0.5f);\n\n\t*out_style = button;\n\tif (duplicate_styles) {\n\t\tint i;\n\t\tfor (i=0; i<n_dups; ++i) {\n\t\t\t*duplicate_styles[i] = button;\n\t\t}\n\t}\n\t}\n\n}\n\nstatic void style_toggle(struct nk_context* ctx, struct nk_style_toggle* out_style)\n{\n\tstruct nk_style_toggle toggle = *out_style;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\n\tstyle_item_color(ctx, \"Normal:\", &toggle.normal);\n\tstyle_item_color(ctx, \"Hover:\", &toggle.hover);\n\tstyle_item_color(ctx, \"Active:\", &toggle.active);\n\tstyle_item_color(ctx, \"Cursor Normal:\", &toggle.cursor_normal);\n\tstyle_item_color(ctx, \"Cursor Hover:\", &toggle.cursor_hover);\n\n\tstyle_rgb(ctx, \"Border:\", &toggle.border_color);\n\tstyle_rgb(ctx, \"Text Background:\", &toggle.text_background);\n\tstyle_rgb(ctx, \"Text Normal:\", &toggle.text_normal);\n\tstyle_rgb(ctx, \"Text Hover:\", &toggle.text_hover);\n\tstyle_rgb(ctx, \"Text Active:\", &toggle.text_active);\n\n\tstyle_vec2(ctx, \"Padding:\", &toggle.padding);\n\tstyle_vec2(ctx, \"Touch Padding:\", &toggle.touch_padding);\n\n\tnk_property_float(ctx, \"#Border:\", -100.0f, &toggle.border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Spacing:\", -100.0f, &toggle.spacing, 100.0f, 1,0.5f);\n\n\t*out_style = toggle;\n\n}\n\nstatic void\nstyle_selectable(struct nk_context* ctx, struct nk_style_selectable* out_style)\n{\n\tstruct nk_style_selectable select = *out_style;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\n\tstyle_item_color(ctx, \"Normal:\", &select.normal);\n\tstyle_item_color(ctx, \"Hover:\", &select.hover);\n\tstyle_item_color(ctx, \"Pressed:\", &select.pressed);\n\tstyle_item_color(ctx, \"Normal Active:\", &select.normal_active);\n\tstyle_item_color(ctx, \"Hover Active:\", &select.hover_active);\n\tstyle_item_color(ctx, \"Pressed Active:\", &select.pressed_active);\n\n\tstyle_rgb(ctx, \"Text Normal:\", &select.text_normal);\n\tstyle_rgb(ctx, \"Text Hover:\", &select.text_hover);\n\tstyle_rgb(ctx, \"Text Pressed:\", &select.text_pressed);\n\tstyle_rgb(ctx, \"Text Normal Active:\", &select.text_normal_active);\n\tstyle_rgb(ctx, \"Text Hover Active:\", &select.text_hover_active);\n\tstyle_rgb(ctx, \"Text Pressed Active:\", &select.text_pressed_active);\n\n\tstyle_vec2(ctx, \"Padding:\", &select.padding);\n\tstyle_vec2(ctx, \"Image Padding:\", &select.image_padding);\n\tstyle_vec2(ctx, \"Touch Padding:\", &select.touch_padding);\n\n\tnk_property_float(ctx, \"#Rounding:\", -100.0f, &select.rounding, 100.0f, 1,0.5f);\n\n\n\t*out_style = select;\n}\n\nstatic void\nstyle_slider(struct nk_context* ctx, struct nk_style_slider* out_style)\n{\n\tstruct nk_style_slider slider = *out_style;\n\tstruct nk_style_button* dups[1];\n\tnk_bool show_buttons_b;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\n\tstyle_item_color(ctx, \"Normal:\", &slider.normal);\n\tstyle_item_color(ctx, \"Hover:\", &slider.hover);\n\tstyle_item_color(ctx, \"Active:\", &slider.active);\n\n\tstyle_rgb(ctx, \"Bar Normal:\", &slider.bar_normal);\n\tstyle_rgb(ctx, \"Bar Hover:\", &slider.bar_hover);\n\tstyle_rgb(ctx, \"Bar Active:\", &slider.bar_active);\n\tstyle_rgb(ctx, \"Bar Filled:\", &slider.bar_filled);\n\n\tstyle_item_color(ctx, \"Cursor Normal:\", &slider.cursor_normal);\n\tstyle_item_color(ctx, \"Cursor Hover:\", &slider.cursor_hover);\n\tstyle_item_color(ctx, \"Cursor Active:\", &slider.cursor_active);\n\n\tstyle_vec2(ctx, \"Cursor Size:\", &slider.cursor_size);\n\tstyle_vec2(ctx, \"Padding:\", &slider.padding);\n\tstyle_vec2(ctx, \"Spacing:\", &slider.spacing);\n\n\tnk_property_float(ctx, \"#Bar Height:\", -100.0f, &slider.bar_height, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Rounding:\", -100.0f, &slider.rounding, 100.0f, 1,0.5f);\n\n\tnk_layout_row_dynamic(ctx, 30, 1);\n\tshow_buttons_b = (nk_bool)slider.show_buttons;\n\tnk_checkbox_label(ctx, \"Show Buttons\", &show_buttons_b);\n\tslider.show_buttons = (int)show_buttons_b;\n\n\tif (slider.show_buttons) {\n\t\tnk_layout_row_dynamic(ctx, 30, 2);\n\t\tnk_label(ctx, \"Inc Symbol:\", NK_TEXT_LEFT);\n\t\tslider.inc_symbol = nk_combo(ctx, symbols, NK_SYMBOL_MAX, slider.inc_symbol, 25, nk_vec2(200,200));\n\t\tnk_label(ctx, \"Dec Symbol:\", NK_TEXT_LEFT);\n\t\tslider.dec_symbol = nk_combo(ctx, symbols, NK_SYMBOL_MAX, slider.dec_symbol, 25, nk_vec2(200,200));\n\n\t\t/* necessary or do tree's always take the whole width? */\n\t\t/* nk_layout_row_dynamic(ctx, 30, 1); */\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Slider Buttons\", NK_MINIMIZED)) {\n\t\t\tdups[0] = &ctx->style.slider.dec_button;\n\t\t\tstyle_button(ctx, &ctx->style.slider.inc_button, dups, 1);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t}\n\n\t*out_style = slider;\n}\n\nstatic void\nstyle_progress(struct nk_context* ctx, struct nk_style_progress* out_style)\n{\n\tstruct nk_style_progress prog = *out_style;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\n\tstyle_item_color(ctx, \"Normal:\", &prog.normal);\n\tstyle_item_color(ctx, \"Hover:\", &prog.hover);\n\tstyle_item_color(ctx, \"Active:\", &prog.active);\n\tstyle_item_color(ctx, \"Cursor Normal:\", &prog.cursor_normal);\n\tstyle_item_color(ctx, \"Cursor Hover:\", &prog.cursor_hover);\n\tstyle_item_color(ctx, \"Cursor Active:\", &prog.cursor_active);\n\n\t/* TODO rgba? */\n\tstyle_rgb(ctx, \"Border Color:\", &prog.border_color);\n\tstyle_rgb(ctx, \"Cursor Border Color:\", &prog.cursor_border_color);\n\n\tstyle_vec2(ctx, \"Padding:\", &prog.padding);\n\n\tnk_property_float(ctx, \"#Rounding:\", -100.0f, &prog.rounding, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Border:\", -100.0f, &prog.border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Cursor Rounding:\", -100.0f, &prog.cursor_rounding, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Cursor Border:\", -100.0f, &prog.cursor_border, 100.0f, 1,0.5f);\n\n\n\t*out_style = prog;\n}\n\nstatic void\nstyle_scrollbars(struct nk_context* ctx, struct nk_style_scrollbar* out_style, struct nk_style_scrollbar** duplicate_styles, int n_dups)\n{\n\tstruct nk_style_scrollbar scroll = *out_style;\n\tstruct nk_style_button* dups[3];\n\tnk_bool show_buttons_b;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\n\tstyle_item_color(ctx, \"Normal:\", &scroll.normal);\n\tstyle_item_color(ctx, \"Hover:\", &scroll.hover);\n\tstyle_item_color(ctx, \"Active:\", &scroll.active);\n\tstyle_item_color(ctx, \"Cursor Normal:\", &scroll.cursor_normal);\n\tstyle_item_color(ctx, \"Cursor Hover:\", &scroll.cursor_hover);\n\tstyle_item_color(ctx, \"Cursor Active:\", &scroll.cursor_active);\n\n\t/* TODO rgba? */\n\tstyle_rgb(ctx, \"Border Color:\", &scroll.border_color);\n\tstyle_rgb(ctx, \"Cursor Border Color:\", &scroll.cursor_border_color);\n\n\tstyle_vec2(ctx, \"Padding:\", &scroll.padding);\n\n\tnk_property_float(ctx, \"#Border:\", -100.0f, &scroll.border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Rounding:\", -100.0f, &scroll.rounding, 100.0f, 1,0.5f);\n\n\t/* TODO naming inconsistency with style_scrollress? */\n\tnk_property_float(ctx, \"#Cursor Border:\", -100.0f, &scroll.border_cursor, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Cursor Rounding:\", -100.0f, &scroll.rounding_cursor, 100.0f, 1,0.5f);\n\n\t/* TODO what is wrong with scrollbar buttons?  Also look into controlling the total width (and height) of scrollbars */\n\tnk_layout_row_dynamic(ctx, 30, 1);\n\tshow_buttons_b = (nk_bool)scroll.show_buttons;\n\tnk_checkbox_label(ctx, \"Show Buttons\", &show_buttons_b);\n\tscroll.show_buttons = (int)show_buttons_b;\n\n\tif (scroll.show_buttons) {\n\t\tnk_layout_row_dynamic(ctx, 30, 2);\n\t\tnk_label(ctx, \"Inc Symbol:\", NK_TEXT_LEFT);\n\t\tscroll.inc_symbol = nk_combo(ctx, symbols, NK_SYMBOL_MAX, scroll.inc_symbol, 25, nk_vec2(200,200));\n\t\tnk_label(ctx, \"Dec Symbol:\", NK_TEXT_LEFT);\n\t\tscroll.dec_symbol = nk_combo(ctx, symbols, NK_SYMBOL_MAX, scroll.dec_symbol, 25, nk_vec2(200,200));\n\n\t\t/* nk_layout_row_dynamic(ctx, 30, 1); */\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Scrollbar Buttons\", NK_MINIMIZED)) {\n\t\t\tdups[0] = &ctx->style.scrollh.dec_button;\n\t\t\tdups[1] = &ctx->style.scrollv.inc_button;\n\t\t\tdups[2] = &ctx->style.scrollv.dec_button;\n\t\t\tstyle_button(ctx, &ctx->style.scrollh.inc_button, dups, 3);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\t}\n\n\t*out_style = scroll;\n\tif (duplicate_styles) {\n\t\tint i;\n\t\tfor (i=0; i<n_dups; ++i) {\n\t\t\t*duplicate_styles[i] = scroll;\n\t\t}\n\t}\n}\n\nstatic void\nstyle_edit(struct nk_context* ctx, struct nk_style_edit* out_style)\n{\n\tstruct nk_style_edit edit = *out_style;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\n\tstyle_item_color(ctx, \"Normal:\", &edit.normal);\n\tstyle_item_color(ctx, \"Hover:\", &edit.hover);\n\tstyle_item_color(ctx, \"Active:\", &edit.active);\n\n\tstyle_rgb(ctx, \"Cursor Normal:\", &edit.cursor_normal);\n\tstyle_rgb(ctx, \"Cursor Hover:\", &edit.cursor_hover);\n\tstyle_rgb(ctx, \"Cursor Text Normal:\", &edit.cursor_text_normal);\n\tstyle_rgb(ctx, \"Cursor Text Hover:\", &edit.cursor_text_hover);\n\tstyle_rgb(ctx, \"Border:\", &edit.border_color);\n\tstyle_rgb(ctx, \"Text Normal:\", &edit.text_normal);\n\tstyle_rgb(ctx, \"Text Hover:\", &edit.text_hover);\n\tstyle_rgb(ctx, \"Text Active:\", &edit.text_active);\n\tstyle_rgb(ctx, \"Selected Normal:\", &edit.selected_normal);\n\tstyle_rgb(ctx, \"Selected Hover:\", &edit.selected_hover);\n\tstyle_rgb(ctx, \"Selected Text Normal:\", &edit.selected_text_normal);\n\tstyle_rgb(ctx, \"Selected Text Hover:\", &edit.selected_text_hover);\n\n\tstyle_vec2(ctx, \"Scrollbar Size:\", &edit.scrollbar_size);\n\tstyle_vec2(ctx, \"Padding:\", &edit.padding);\n\n\tnk_property_float(ctx, \"#Row Padding:\", -100.0f, &edit.row_padding, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Cursor Size:\", -100.0f, &edit.cursor_size, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Border:\", -100.0f, &edit.border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Rounding:\", -100.0f, &edit.rounding, 100.0f, 1,0.5f);\n\n\n\t*out_style = edit;\n}\n\nstatic void\nstyle_property(struct nk_context* ctx, struct nk_style_property* out_style)\n{\n\tstruct nk_style_property property = *out_style;\n\tstruct nk_style_button* dups[1];\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\n\tstyle_item_color(ctx, \"Normal:\", &property.normal);\n\tstyle_item_color(ctx, \"Hover:\", &property.hover);\n\tstyle_item_color(ctx, \"Active:\", &property.active);\n\n\tstyle_rgb(ctx, \"Border:\", &property.border_color);\n\tstyle_rgb(ctx, \"Label Normal:\", &property.label_normal);\n\tstyle_rgb(ctx, \"Label Hover:\", &property.label_hover);\n\tstyle_rgb(ctx, \"Label Active:\", &property.label_active);\n\n\tstyle_vec2(ctx, \"Padding:\", &property.padding);\n\n\t/* TODO check weird hover bug with properties, happens in overview basic section too */\n\tnk_property_float(ctx, \"#Border:\", -100.0f, &property.border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Rounding:\", -100.0f, &property.rounding, 100.0f, 1,0.5f);\n\n\t/* there is no property.show_buttons, they're always there */\n\n\tnk_label(ctx, \"Left Symbol:\", NK_TEXT_LEFT);\n\tproperty.sym_left = nk_combo(ctx, symbols, NK_SYMBOL_MAX, property.sym_left, 25, nk_vec2(200,200));\n\tnk_label(ctx, \"Right Symbol:\", NK_TEXT_LEFT);\n\tproperty.sym_right = nk_combo(ctx, symbols, NK_SYMBOL_MAX, property.sym_right, 25, nk_vec2(200,200));\n\n\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Property Buttons\", NK_MINIMIZED)) {\n\t\tdups[0] = &property.dec_button;\n\t\tstyle_button(ctx, &property.inc_button, dups, 1);\n\t\tnk_tree_pop(ctx);\n\t}\n\n\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Property Edit\", NK_MINIMIZED)) {\n\t\tstyle_edit(ctx, &ctx->style.property.edit);\n\t\tnk_tree_pop(ctx);\n\t}\n\n\t*out_style = property;\n}\n\nstatic void\nstyle_chart(struct nk_context* ctx, struct nk_style_chart* out_style)\n{\n\tstruct nk_style_chart chart = *out_style;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\n\tstyle_item_color(ctx, \"Background:\", &chart.background);\n\n\tstyle_rgb(ctx, \"Border:\", &chart.border_color);\n\tstyle_rgb(ctx, \"Selected Color:\", &chart.selected_color);\n\tstyle_rgb(ctx, \"Color:\", &chart.color);\n\n\tstyle_vec2(ctx, \"Padding:\", &chart.padding);\n\n\tnk_property_float(ctx, \"#Border:\", -100.0f, &chart.border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Rounding:\", -100.0f, &chart.rounding, 100.0f, 1,0.5f);\n\n\t*out_style = chart;\n}\n\nstatic void\nstyle_combo(struct nk_context* ctx, struct nk_style_combo* out_style)\n{\n\tstruct nk_style_combo combo = *out_style;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\n\tstyle_item_color(ctx, \"Normal:\", &combo.normal);\n\tstyle_item_color(ctx, \"Hover:\", &combo.hover);\n\tstyle_item_color(ctx, \"Active:\", &combo.active);\n\n\tstyle_rgb(ctx, \"Border:\", &combo.border_color);\n\tstyle_rgb(ctx, \"Label Normal:\", &combo.label_normal);\n\tstyle_rgb(ctx, \"Label Hover:\", &combo.label_hover);\n\tstyle_rgb(ctx, \"Label Active:\", &combo.label_active);\n\n\tnk_label(ctx, \"Normal Symbol:\", NK_TEXT_LEFT);\n\tcombo.sym_normal = nk_combo(ctx, symbols, NK_SYMBOL_MAX, combo.sym_normal, 25, nk_vec2(200,200));\n\tnk_label(ctx, \"Hover Symbol:\", NK_TEXT_LEFT);\n\tcombo.sym_hover = nk_combo(ctx, symbols, NK_SYMBOL_MAX, combo.sym_hover, 25, nk_vec2(200,200));\n\tnk_label(ctx, \"Active Symbol:\", NK_TEXT_LEFT);\n\tcombo.sym_active = nk_combo(ctx, symbols, NK_SYMBOL_MAX, combo.sym_active, 25, nk_vec2(200,200));\n\n\tstyle_vec2(ctx, \"Content Padding:\", &combo.content_padding);\n\tstyle_vec2(ctx, \"Button Padding:\", &combo.button_padding);\n\tstyle_vec2(ctx, \"Spacing:\", &combo.spacing);\n\n\tnk_property_float(ctx, \"#Border:\", -100.0f, &combo.border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Rounding:\", -100.0f, &combo.rounding, 100.0f, 1,0.5f);\n\n\t*out_style = combo;\n}\n\nstatic void\nstyle_tab(struct nk_context* ctx, struct nk_style_tab* out_style)\n{\n\tstruct nk_style_tab tab = *out_style;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\n\tstyle_item_color(ctx, \"Background:\", &tab.background);\n\n\tstyle_rgb(ctx, \"Border:\", &tab.border_color);\n\tstyle_rgb(ctx, \"Text:\", &tab.text);\n\n\t/*\n\t * FTR, I feel these fields are misnamed and should be sym_minimized and sym_maximized since they are\n\t * what show in that state, not the button to push to get to that state\n\t */\n\tnk_label(ctx, \"Minimized Symbol:\", NK_TEXT_LEFT);\n\ttab.sym_minimize = nk_combo(ctx, symbols, NK_SYMBOL_MAX, tab.sym_minimize, 25, nk_vec2(200,200));\n\tnk_label(ctx, \"Maxmized Symbol:\", NK_TEXT_LEFT);\n\ttab.sym_maximize = nk_combo(ctx, symbols, NK_SYMBOL_MAX, tab.sym_maximize, 25, nk_vec2(200,200));\n\n\tstyle_vec2(ctx, \"Padding:\", &tab.padding);\n\tstyle_vec2(ctx, \"Spacing:\", &tab.spacing);\n\n\tnk_property_float(ctx, \"#Indent:\", -100.0f, &tab.indent, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Border:\", -100.0f, &tab.border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Rounding:\", -100.0f, &tab.rounding, 100.0f, 1,0.5f);\n\n\n\n\t*out_style = tab;\n}\n\nstatic void\nstyle_window_header(struct nk_context* ctx, struct nk_style_window_header* out_style)\n{\n\tstruct nk_style_window_header header = *out_style;\n\tstruct nk_style_button* dups[1];\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\n\tstyle_item_color(ctx, \"Normal:\", &header.normal);\n\tstyle_item_color(ctx, \"Hover:\", &header.hover);\n\tstyle_item_color(ctx, \"Active:\", &header.active);\n\n\tstyle_rgb(ctx, \"Label Normal:\", &header.label_normal);\n\tstyle_rgb(ctx, \"Label Hover:\", &header.label_hover);\n\tstyle_rgb(ctx, \"Label Active:\", &header.label_active);\n\n\tstyle_vec2(ctx, \"Label Padding:\", &header.label_padding);\n\tstyle_vec2(ctx, \"Padding:\", &header.padding);\n\tstyle_vec2(ctx, \"Spacing:\", &header.spacing);\n\n#define NUM_ALIGNS 2\n\t{\n\tconst char* alignments[NUM_ALIGNS] = { \"LEFT\", \"RIGHT\" };\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\tnk_label(ctx, \"Button Alignment:\", NK_TEXT_LEFT);\n\theader.align = nk_combo(ctx, alignments, NUM_ALIGNS, header.align, 25, nk_vec2(200,200));\n\t}\n#undef NUM_ALIGNS\n\n\tnk_label(ctx, \"Close Symbol:\", NK_TEXT_LEFT);\n\theader.close_symbol = nk_combo(ctx, symbols, NK_SYMBOL_MAX, header.close_symbol, 25, nk_vec2(200,200));\n\tnk_label(ctx, \"Minimize Symbol:\", NK_TEXT_LEFT);\n\theader.minimize_symbol = nk_combo(ctx, symbols, NK_SYMBOL_MAX, header.minimize_symbol, 25, nk_vec2(200,200));\n\tnk_label(ctx, \"Maximize Symbol:\", NK_TEXT_LEFT);\n\theader.maximize_symbol = nk_combo(ctx, symbols, NK_SYMBOL_MAX, header.maximize_symbol, 25, nk_vec2(200,200));\n\n\t/* necessary or do tree's always take the whole width? */\n\t/* nk_layout_row_dynamic(ctx, 30, 1); */\n\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Close and Minimize Button\", NK_MINIMIZED)) {\n\t\tdups[0] = &header.minimize_button;\n\t\tstyle_button(ctx, &header.close_button, dups, 1);\n\t\tnk_tree_pop(ctx);\n\t}\n\n\t*out_style = header;\n}\n\nstatic void\nstyle_window(struct nk_context* ctx, struct nk_style_window* out_style)\n{\n\tstatic const char* tooltip_positions[] =\n\t{\n\t\t\"TOP_LEFT\",\n\t\t\"TOP_CENTER\",\n\t\t\"TOP_RIGHT\",\n\n\t\t\"MIDDLE_LEFT\",\n\t\t\"MIDDLE_CENTER\",\n\t\t\"MIDDLE_RIGHT\",\n\n\t\t\"BOTTOM_LEFT\",\n\t\t\"BOTTOM_CENTER\",\n\t\t\"BOTTOM_RIGHT\"\n\t};\n\t/*static int cur_tooltip_pos = NK_TOP_LEFT;*/\n\n\tstruct nk_style_window win = *out_style;\n\n\tnk_layout_row_dynamic(ctx, 30, 2);\n\n\tstyle_rgb(ctx, \"Background:\", &win.background);\n\n\tstyle_item_color(ctx, \"Fixed Background:\", &win.fixed_background);\n\n\tstyle_rgb(ctx, \"Border:\", &win.border_color);\n\tstyle_rgb(ctx, \"Popup Border:\", &win.popup_border_color);\n\tstyle_rgb(ctx, \"Combo Border:\", &win.combo_border_color);\n\tstyle_rgb(ctx, \"Contextual Border:\", &win.contextual_border_color);\n\tstyle_rgb(ctx, \"Menu Border:\", &win.menu_border_color);\n\tstyle_rgb(ctx, \"Group Border:\", &win.group_border_color);\n\tstyle_rgb(ctx, \"Tooltip Border:\", &win.tooltip_border_color);\n\n\tstyle_item_color(ctx, \"Scaler:\", &win.scaler);\n\n\tstyle_vec2(ctx, \"Spacing:\", &win.spacing);\n\tstyle_vec2(ctx, \"Scrollbar Size:\", &win.scrollbar_size);\n\tstyle_vec2(ctx, \"Min Size:\", &win.min_size);\n\tstyle_vec2(ctx, \"Padding:\", &win.padding);\n\tstyle_vec2(ctx, \"Group Padding:\", &win.group_padding);\n\tstyle_vec2(ctx, \"Popup Padding:\", &win.popup_padding);\n\tstyle_vec2(ctx, \"Combo Padding:\", &win.combo_padding);\n\tstyle_vec2(ctx, \"Contextual Padding:\", &win.contextual_padding);\n\tstyle_vec2(ctx, \"Menu Padding:\", &win.menu_padding);\n\tstyle_vec2(ctx, \"Tooltip Padding:\", &win.tooltip_padding);\n\n    nk_label(ctx, \"Tooltip Origin\", NK_TEXT_LEFT);\n    win.tooltip_origin = nk_combo(ctx, tooltip_positions, NK_LEN(tooltip_positions), win.tooltip_origin, 25, nk_vec2(200, 200));\n    style_vec2(ctx, \"Tooltip offset:\", &win.tooltip_offset);\n\n\tnk_property_float(ctx, \"#Rounding:\", -100.0f, &win.rounding, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Combo Border:\", -100.0f, &win.combo_border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Contextual Border:\", -100.0f, &win.contextual_border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Menu Border:\", -100.0f, &win.menu_border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Group Border:\", -100.0f, &win.group_border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Tooltip Border:\", -100.0f, &win.tooltip_border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Popup Border:\", -100.0f, &win.popup_border, 100.0f, 1,0.5f);\n\tnk_property_float(ctx, \"#Border:\", -100.0f, &win.border, 100.0f, 1,0.5f);\n\n\tnk_layout_row_dynamic(ctx, 30, 1);\n\tnk_property_float(ctx, \"#Min Row Height Padding:\", -100.0f, &win.min_row_height_padding, 100.0f, 1,0.5f);\n\n\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Window Header\", NK_MINIMIZED)) {\n\t\tstyle_window_header(ctx, &win.header);\n\t\tnk_tree_pop(ctx);\n\t}\n\n\t*out_style = win;\n}\n\nstatic int\nstyle_configurator(struct nk_context *ctx, struct nk_color color_table[NK_COLOR_COUNT])\n{\n\t/* window flags */\n\tint border = nk_true;\n\tint resize = nk_true;\n\tint movable = nk_true;\n\tint no_scrollbar = nk_false;\n\tint scale_left = nk_false;\n\tnk_flags window_flags = 0;\n\tint minimizable = nk_true;\n\tstruct nk_style *style = NULL;\n\tstruct nk_style_button* dups[1];\n\n\t/* window flags */\n\twindow_flags = 0;\n\tif (border) window_flags |= NK_WINDOW_BORDER;\n\tif (resize) window_flags |= NK_WINDOW_SCALABLE;\n\tif (movable) window_flags |= NK_WINDOW_MOVABLE;\n\tif (no_scrollbar) window_flags |= NK_WINDOW_NO_SCROLLBAR;\n\tif (scale_left) window_flags |= NK_WINDOW_SCALE_LEFT;\n\tif (minimizable) window_flags |= NK_WINDOW_MINIMIZABLE;\n\n\tstyle = &ctx->style;\n\n\tif (nk_begin(ctx, \"Configurator\", nk_rect(10, 10, 400, 600), window_flags))\n\t{\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Global Colors\", NK_MINIMIZED)) {\n\t\t\tstyle_global_colors(ctx, color_table);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Text\", NK_MINIMIZED)) {\n\t\t\tstyle_text(ctx, &style->text);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Button\", NK_MINIMIZED)) {\n\t\t\tstyle_button(ctx, &style->button, NULL, 0);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Contextual Button\", NK_MINIMIZED)) {\n\t\t\tstyle_button(ctx, &style->contextual_button, NULL, 0);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Menu Button\", NK_MINIMIZED)) {\n\t\t\tstyle_button(ctx, &style->menu_button, NULL, 0);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Combo Buttons\", NK_MINIMIZED)) {\n\t\t\tstyle_button(ctx, &style->combo.button, NULL, 0);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Tab Min/Max Buttons\", NK_MINIMIZED)) {\n\t\t\tdups[0] = &style->tab.tab_maximize_button;\n\t\t\tstyle_button(ctx, &style->tab.tab_minimize_button, dups, 1);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Node Min/Max Buttons\", NK_MINIMIZED)) {\n\t\t\tdups[0] = &style->tab.node_maximize_button;\n\t\t\tstyle_button(ctx, &style->tab.node_minimize_button, dups, 1);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Window Header Close Buttons\", NK_MINIMIZED)) {\n\t\t\tstyle_button(ctx, &style->window.header.close_button, NULL, 0);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Window Header Minimize Buttons\", NK_MINIMIZED)) {\n\t\t\tstyle_button(ctx, &style->window.header.minimize_button, NULL, 0);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Checkbox\", NK_MINIMIZED)) {\n\t\t\tstyle_toggle(ctx, &style->checkbox);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Option\", NK_MINIMIZED)) {\n\t\t\tstyle_toggle(ctx, &style->option);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Selectable\", NK_MINIMIZED)) {\n\t\t\tstyle_selectable(ctx, &style->selectable);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Slider\", NK_MINIMIZED)) {\n\t\t\tstyle_slider(ctx, &style->slider);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Progress\", NK_MINIMIZED)) {\n\t\t\tstyle_progress(ctx, &style->progress);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Scrollbars\", NK_MINIMIZED)) {\n\t\t\tstruct nk_style_scrollbar* dups[1];\n\t\t\tdups[0] = &style->scrollv;\n\t\t\tstyle_scrollbars(ctx, &style->scrollh, dups, 1);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Edit\", NK_MINIMIZED)) {\n\t\t\tstyle_edit(ctx, &style->edit);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Property\", NK_MINIMIZED)) {\n\t\t\tstyle_property(ctx, &style->property);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Chart\", NK_MINIMIZED)) {\n\t\t\tstyle_chart(ctx, &style->chart);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Combo\", NK_MINIMIZED)) {\n\t\t\tstyle_combo(ctx, &style->combo);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Tab\", NK_MINIMIZED)) {\n\t\t\tstyle_tab(ctx, &style->tab);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tif (nk_tree_push(ctx, NK_TREE_TAB, \"Window\", NK_MINIMIZED)) {\n\t\t\tstyle_window(ctx, &style->window);\n\t\t\tnk_tree_pop(ctx);\n\t\t}\n\n\t\tnk_layout_row_dynamic(ctx, 30, 1);\n\t\tif (nk_button_label(ctx, \"Reset all styles to defaults\")) {\n\t\t\tmemcpy(color_table, nk_default_color_style, sizeof(nk_default_color_style));\n\t\t\tnk_style_default(ctx);\n\t\t}\n\n\t}\n\n\tnk_end(ctx);\n\treturn !nk_window_is_closed(ctx, \"Configurator\");\n}\n"
  },
  {
    "path": "demo/d3d11/build.bat",
    "content": "@echo off\n\nrem This will use VS2015 for compiler\ncall \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat\" x86\n\nfxc.exe /nologo /T vs_4_0_level_9_0 /E vs /O3 /Zpc /Ges /Fh nuklear_d3d11_vertex_shader.h /Vn nk_d3d11_vertex_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv nuklear_d3d11.hlsl\nfxc.exe /nologo /T ps_4_0_level_9_0 /E ps /O3 /Zpc /Ges /Fh nuklear_d3d11_pixel_shader.h /Vn nk_d3d11_pixel_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv nuklear_d3d11.hlsl\n\ncl /D_CRT_SECURE_NO_DEPRECATE /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib dxguid.lib d3d11.lib /link /incremental:no\n"
  },
  {
    "path": "demo/d3d11/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n#define COBJMACROS\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <d3d11.h>\n#include <stdio.h>\n#include <string.h>\n#include <limits.h>\n#include <time.h>\n\n#define WINDOW_WIDTH 800\n#define WINDOW_HEIGHT 600\n\n#define MAX_VERTEX_BUFFER 512 * 1024\n#define MAX_INDEX_BUFFER 128 * 1024\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_D3D11_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_d3d11.h\"\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nstatic IDXGISwapChain *swap_chain;\nstatic ID3D11Device *device;\nstatic ID3D11DeviceContext *context;\nstatic ID3D11RenderTargetView* rt_view;\n\nstatic void\nset_swap_chain_size(int width, int height)\n{\n    ID3D11Texture2D *back_buffer;\n    D3D11_RENDER_TARGET_VIEW_DESC desc;\n    HRESULT hr;\n\n    if (rt_view)\n        ID3D11RenderTargetView_Release(rt_view);\n\n    ID3D11DeviceContext_OMSetRenderTargets(context, 0, NULL, NULL);\n\n    hr = IDXGISwapChain_ResizeBuffers(swap_chain, 0, width, height, DXGI_FORMAT_UNKNOWN, 0);\n    if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DRIVER_INTERNAL_ERROR)\n    {\n        /* to recover from this, you'll need to recreate device and all the resources */\n        MessageBoxW(NULL, L\"DXGI device is removed or reset!\", L\"Error\", 0);\n        exit(0);\n    }\n    assert(SUCCEEDED(hr));\n\n    memset(&desc, 0, sizeof(desc));\n    desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n    desc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;\n\n    hr = IDXGISwapChain_GetBuffer(swap_chain, 0, &IID_ID3D11Texture2D, (void **)&back_buffer);\n    assert(SUCCEEDED(hr));\n\n    hr = ID3D11Device_CreateRenderTargetView(device, (ID3D11Resource *)back_buffer, &desc, &rt_view);\n    assert(SUCCEEDED(hr));\n\n    ID3D11Texture2D_Release(back_buffer);\n}\n\nstatic LRESULT CALLBACK\nWindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)\n{\n    switch (msg)\n    {\n    case WM_DESTROY:\n        PostQuitMessage(0);\n        return 0;\n\n    case WM_SIZE:\n        if (swap_chain)\n        {\n            int width = LOWORD(lparam);\n            int height = HIWORD(lparam);\n            set_swap_chain_size(width, height);\n            nk_d3d11_resize(context, width, height);\n        }\n        break;\n    }\n\n    if (nk_d3d11_handle_event(wnd, msg, wparam, lparam))\n        return 0;\n\n    return DefWindowProcW(wnd, msg, wparam, lparam);\n}\n\nint main(void)\n{\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n\n    WNDCLASSW wc;\n    RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };\n    DWORD style = WS_OVERLAPPEDWINDOW;\n    DWORD exstyle = WS_EX_APPWINDOW;\n    HWND wnd;\n    int running = 1;\n    HRESULT hr;\n    D3D_FEATURE_LEVEL feature_level;\n    DXGI_SWAP_CHAIN_DESC swap_chain_desc;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    /* Win32 */\n    memset(&wc, 0, sizeof(wc));\n    wc.style = CS_DBLCLKS;\n    wc.lpfnWndProc = WindowProc;\n    wc.hInstance = GetModuleHandleW(0);\n    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);\n    wc.hCursor = LoadCursor(NULL, IDC_ARROW);\n    wc.lpszClassName = L\"NuklearWindowClass\";\n    RegisterClassW(&wc);\n\n    AdjustWindowRectEx(&rect, style, FALSE, exstyle);\n\n    wnd = CreateWindowExW(exstyle, wc.lpszClassName, L\"Nuklear Direct3D 11 Demo\",\n        style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,\n        rect.right - rect.left, rect.bottom - rect.top,\n        NULL, NULL, wc.hInstance, NULL);\n\n    /* D3D11 setup */\n    memset(&swap_chain_desc, 0, sizeof(swap_chain_desc));\n    swap_chain_desc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n    swap_chain_desc.BufferDesc.RefreshRate.Numerator = 60;\n    swap_chain_desc.BufferDesc.RefreshRate.Denominator = 1;\n    swap_chain_desc.SampleDesc.Count = 1;\n    swap_chain_desc.SampleDesc.Quality = 0;\n    swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;\n    swap_chain_desc.BufferCount = 1;\n    swap_chain_desc.OutputWindow = wnd;\n    swap_chain_desc.Windowed = TRUE;\n    swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;\n    swap_chain_desc.Flags = 0;\n    if (FAILED(D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_HARDWARE,\n        NULL, 0, NULL, 0, D3D11_SDK_VERSION, &swap_chain_desc,\n        &swap_chain, &device, &feature_level, &context)))\n    {\n        /* if hardware device fails, then try WARP high-performance\n           software rasterizer, this is useful for RDP sessions */\n        hr = D3D11CreateDeviceAndSwapChain(NULL, D3D_DRIVER_TYPE_WARP,\n            NULL, 0, NULL, 0, D3D11_SDK_VERSION, &swap_chain_desc,\n            &swap_chain, &device, &feature_level, &context);\n        assert(SUCCEEDED(hr));\n    }\n    set_swap_chain_size(WINDOW_WIDTH, WINDOW_HEIGHT);\n\n    /* GUI */\n    ctx = nk_d3d11_init(device, WINDOW_WIDTH, WINDOW_HEIGHT, MAX_VERTEX_BUFFER, MAX_INDEX_BUFFER);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {struct nk_font_atlas *atlas;\n    nk_d3d11_font_stash_begin(&atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, \"../../extra_font/Roboto-Regular.ttf\", 14, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_d3d11_font_stash_end();\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &droid->handle)*/;}\n\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (running)\n    {\n        /* Input */\n        MSG msg;\n        nk_input_begin(ctx);\n        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))\n        {\n            if (msg.message == WM_QUIT)\n                running = 0;\n            TranslateMessage(&msg);\n            DispatchMessageW(&msg);\n        }\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 22, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        ID3D11DeviceContext_ClearRenderTargetView(context, rt_view, &bg.r);\n        ID3D11DeviceContext_OMSetRenderTargets(context, 1, &rt_view, NULL);\n        nk_d3d11_render(context, NK_ANTI_ALIASING_ON);\n        hr = IDXGISwapChain_Present(swap_chain, 1, 0);\n        if (hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DEVICE_REMOVED) {\n            /* to recover from this, you'll need to recreate device and all the resources */\n            MessageBoxW(NULL, L\"D3D11 device is lost or removed!\", L\"Error\", 0);\n            break;\n        } else if (hr == DXGI_STATUS_OCCLUDED) {\n            /* window is not visible, so vsync won't work. Let's sleep a bit to reduce CPU usage */\n            Sleep(10);\n        }\n        assert(SUCCEEDED(hr));\n    }\n\n    ID3D11DeviceContext_ClearState(context);\n    nk_d3d11_shutdown();\n    ID3D11RenderTargetView_Release(rt_view);\n    ID3D11DeviceContext_Release(context);\n    ID3D11Device_Release(device);\n    IDXGISwapChain_Release(swap_chain);\n    UnregisterClassW(wc.lpszClassName, wc.hInstance);\n    return 0;\n}\n"
  },
  {
    "path": "demo/d3d11/nuklear_d3d11.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_D3D11_H_\n#define NK_D3D11_H_\n\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n\ntypedef struct ID3D11Device ID3D11Device;\ntypedef struct ID3D11DeviceContext ID3D11DeviceContext;\n\nNK_API struct nk_context *nk_d3d11_init(ID3D11Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer);\nNK_API void nk_d3d11_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void nk_d3d11_font_stash_end(void);\nNK_API int nk_d3d11_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);\nNK_API void nk_d3d11_render(ID3D11DeviceContext *context, enum nk_anti_aliasing);\nNK_API void nk_d3d11_resize(ID3D11DeviceContext *context, int width, int height);\nNK_API void nk_d3d11_shutdown(void);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_D3D11_IMPLEMENTATION\n\n#define WIN32_LEAN_AND_MEAN\n#define COBJMACROS\n#include <d3d11.h>\n\n#include <stdlib.h>\n#include <stddef.h>\n#include <string.h>\n#include <float.h>\n#include <assert.h>\n\n#include \"nuklear_d3d11_vertex_shader.h\"\n#include \"nuklear_d3d11_pixel_shader.h\"\n\nstruct nk_d3d11_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstatic struct\n{\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    struct nk_buffer cmds;\n\n    struct nk_draw_null_texture tex_null;\n    unsigned int max_vertex_buffer;\n    unsigned int max_index_buffer;\n\n    D3D11_VIEWPORT viewport;\n    ID3D11Device *device;\n    ID3D11RasterizerState *rasterizer_state;\n    ID3D11VertexShader *vertex_shader;\n    ID3D11InputLayout *input_layout;\n    ID3D11Buffer *const_buffer;\n    ID3D11PixelShader *pixel_shader;\n    ID3D11BlendState *blend_state;\n    ID3D11Buffer *index_buffer;\n    ID3D11Buffer *vertex_buffer;\n    ID3D11ShaderResourceView *font_texture_view;\n    ID3D11SamplerState *sampler_state;\n} d3d11;\n\nNK_API void\nnk_d3d11_render(ID3D11DeviceContext *context, enum nk_anti_aliasing AA)\n{\n    const float blend_factor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };\n    const UINT stride = sizeof(struct nk_d3d11_vertex);\n    const UINT offset = 0;\n#ifdef NK_UINT_DRAW_INDEX\n    DXGI_FORMAT index_buffer_format = DXGI_FORMAT_R32_UINT;\n#else\n    DXGI_FORMAT index_buffer_format = DXGI_FORMAT_R16_UINT;\n#endif\n\n    ID3D11DeviceContext_IASetInputLayout(context, d3d11.input_layout);\n    ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &d3d11.vertex_buffer, &stride, &offset);\n    ID3D11DeviceContext_IASetIndexBuffer(context, d3d11.index_buffer, index_buffer_format, 0);\n    ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);\n\n    ID3D11DeviceContext_VSSetShader(context, d3d11.vertex_shader, NULL, 0);\n    ID3D11DeviceContext_VSSetConstantBuffers(context, 0, 1, &d3d11.const_buffer);\n\n    ID3D11DeviceContext_PSSetShader(context, d3d11.pixel_shader, NULL, 0);\n    ID3D11DeviceContext_PSSetSamplers(context, 0, 1, &d3d11.sampler_state);\n\n    ID3D11DeviceContext_OMSetBlendState(context, d3d11.blend_state, blend_factor, 0xffffffff);\n    ID3D11DeviceContext_RSSetState(context, d3d11.rasterizer_state);\n    ID3D11DeviceContext_RSSetViewports(context, 1, &d3d11.viewport);\n\n    /* Convert from command queue into draw list and draw to screen */\n    {/* load draw vertices & elements directly into vertex + element buffer */\n    D3D11_MAPPED_SUBRESOURCE vertices;\n    D3D11_MAPPED_SUBRESOURCE indices;\n    const struct nk_draw_command *cmd;\n    UINT offset = 0;\n    HRESULT hr;\n\n    hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &vertices);\n    NK_ASSERT(SUCCEEDED(hr));\n    hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.index_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &indices);\n    NK_ASSERT(SUCCEEDED(hr));\n\n    {/* fill converting configuration */\n        struct nk_convert_config config;\n        NK_STORAGE const struct nk_draw_vertex_layout_element vertex_layout[] = {\n            {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d11_vertex, position)},\n            {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d11_vertex, uv)},\n            {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_d3d11_vertex, col)},\n            {NK_VERTEX_LAYOUT_END}\n        };\n        memset(&config, 0, sizeof(config));\n        config.vertex_layout = vertex_layout;\n        config.vertex_size = sizeof(struct nk_d3d11_vertex);\n        config.vertex_alignment = NK_ALIGNOF(struct nk_d3d11_vertex);\n        config.global_alpha = 1.0f;\n        config.shape_AA = AA;\n        config.line_AA = AA;\n        config.circle_segment_count = 22;\n        config.curve_segment_count = 22;\n        config.arc_segment_count = 22;\n        config.tex_null = d3d11.tex_null;\n\n        {/* setup buffers to load vertices and elements */\n        struct nk_buffer vbuf, ibuf;\n        nk_buffer_init_fixed(&vbuf, vertices.pData, (size_t)d3d11.max_vertex_buffer);\n        nk_buffer_init_fixed(&ibuf, indices.pData, (size_t)d3d11.max_index_buffer);\n        nk_convert(&d3d11.ctx, &d3d11.cmds, &vbuf, &ibuf, &config);}\n    }\n\n    ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.vertex_buffer, 0);\n    ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.index_buffer, 0);\n\n    /* iterate over and execute each draw command */\n    nk_draw_foreach(cmd, &d3d11.ctx, &d3d11.cmds)\n    {\n        D3D11_RECT scissor;\n        ID3D11ShaderResourceView *texture_view = (ID3D11ShaderResourceView *)cmd->texture.ptr;\n        if (!cmd->elem_count) continue;\n\n        scissor.left = (LONG)cmd->clip_rect.x;\n        scissor.right = (LONG)(cmd->clip_rect.x + cmd->clip_rect.w);\n        scissor.top = (LONG)cmd->clip_rect.y;\n        scissor.bottom = (LONG)(cmd->clip_rect.y + cmd->clip_rect.h);\n\n        ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &texture_view);\n        ID3D11DeviceContext_RSSetScissorRects(context, 1, &scissor);\n        ID3D11DeviceContext_DrawIndexed(context, (UINT)cmd->elem_count, offset, 0);\n        offset += cmd->elem_count;\n    }\n    nk_clear(&d3d11.ctx);\n    nk_buffer_clear(&d3d11.cmds);}\n}\n\nstatic void\nnk_d3d11_get_projection_matrix(int width, int height, float *result)\n{\n    const float L = 0.0f;\n    const float R = (float)width;\n    const float T = 0.0f;\n    const float B = (float)height;\n    float matrix[4][4] =\n    {\n        { 0.0f, 0.0f, 0.0f, 0.0f },\n        { 0.0f, 0.0f, 0.0f, 0.0f },\n        { 0.0f, 0.0f, 0.5f, 0.0f },\n        { 0.0f, 0.0f, 0.5f, 1.0f },\n    };\n    matrix[0][0] = 2.0f / (R - L);\n    matrix[1][1] = 2.0f / (T - B);\n    matrix[3][0] = (R + L) / (L - R);\n    matrix[3][1] = (T + B) / (B - T);\n    memcpy(result, matrix, sizeof(matrix));\n}\n\nNK_API void\nnk_d3d11_resize(ID3D11DeviceContext *context, int width, int height)\n{\n    D3D11_MAPPED_SUBRESOURCE mapped;\n    if (SUCCEEDED(ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.const_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped)))\n    {\n        nk_d3d11_get_projection_matrix(width, height, (float *)mapped.pData);\n        ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.const_buffer, 0);\n\n        d3d11.viewport.Width = (float)width;\n        d3d11.viewport.Height = (float)height;\n    }\n}\n\nNK_API int\nnk_d3d11_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)\n{\n    static int insert_toggle = 0;\n    switch (msg)\n    {\n    case WM_KEYDOWN:\n    case WM_KEYUP:\n    case WM_SYSKEYDOWN:\n    case WM_SYSKEYUP:\n    {\n        int down = !((lparam >> 31) & 1);\n        int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);\n\n        switch (wparam)\n        {\n        case VK_SHIFT:\n        case VK_LSHIFT:\n        case VK_RSHIFT:\n            nk_input_key(&d3d11.ctx, NK_KEY_SHIFT, down);\n            return 1;\n\n        case VK_DELETE:\n            nk_input_key(&d3d11.ctx, NK_KEY_DEL, down);\n            return 1;\n\n        case VK_RETURN:\n        case VK_SEPARATOR:\n            nk_input_key(&d3d11.ctx, NK_KEY_ENTER, down);\n            return 1;\n\n        case VK_TAB:\n            nk_input_key(&d3d11.ctx, NK_KEY_TAB, down);\n            return 1;\n\n        case VK_UP:\n            nk_input_key(&d3d11.ctx, NK_KEY_UP, down);\n            return 1;\n\n        case VK_DOWN:\n            nk_input_key(&d3d11.ctx, NK_KEY_DOWN, down);\n            return 1;\n\n        case VK_LEFT:\n            if (ctrl)\n                nk_input_key(&d3d11.ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else\n                nk_input_key(&d3d11.ctx, NK_KEY_LEFT, down);\n            return 1;\n\n        case VK_RIGHT:\n            if (ctrl)\n                nk_input_key(&d3d11.ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else\n                nk_input_key(&d3d11.ctx, NK_KEY_RIGHT, down);\n            return 1;\n\n        case VK_BACK:\n            nk_input_key(&d3d11.ctx, NK_KEY_BACKSPACE, down);\n            return 1;\n\n        case VK_HOME:\n            nk_input_key(&d3d11.ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_START, down);\n            return 1;\n\n        case VK_END:\n            nk_input_key(&d3d11.ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_END, down);\n            return 1;\n\n        case VK_NEXT:\n            nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_DOWN, down);\n            return 1;\n\n        case VK_PRIOR:\n            nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_UP, down);\n            return 1;\n\n        case VK_ESCAPE:\n            nk_input_key(&d3d11.ctx, NK_KEY_TEXT_RESET_MODE, down);\n            return 1;\n\n        case VK_INSERT:\n        /* Only switch on release to avoid repeat issues\n         * kind of confusing since we have to negate it but we're already\n         * hacking it since Nuklear treats them as two separate keys rather\n         * than a single toggle state */\n            if (!down) {\n                insert_toggle = !insert_toggle;\n                if (insert_toggle) {\n                    nk_input_key(&d3d11.ctx, NK_KEY_TEXT_INSERT_MODE, !down);\n                    /* nk_input_key(&d3d11.ctx, NK_KEY_TEXT_REPLACE_MODE, down); */\n                } else {\n                    nk_input_key(&d3d11.ctx, NK_KEY_TEXT_REPLACE_MODE, !down);\n                    /* nk_input_key(&d3d11.ctx, NK_KEY_TEXT_INSERT_MODE, down); */\n                }\n            }\n            return 1;\n\n        case 'A':\n            if (ctrl) {\n                nk_input_key(&d3d11.ctx, NK_KEY_TEXT_SELECT_ALL, down);\n                return 1;\n            }\n            break;\n\n        case 'B':\n            if (ctrl) {\n                nk_input_key(&d3d11.ctx, NK_KEY_TEXT_LINE_START, down);\n                return 1;\n            }\n            break;\n\n        case 'E':\n            if (ctrl) {\n                nk_input_key(&d3d11.ctx, NK_KEY_TEXT_LINE_END, down);\n                return 1;\n            }\n            break;\n\n        case 'C':\n            if (ctrl) {\n                nk_input_key(&d3d11.ctx, NK_KEY_COPY, down);\n                return 1;\n            }\n            break;\n\n        case 'V':\n            if (ctrl) {\n                nk_input_key(&d3d11.ctx, NK_KEY_PASTE, down);\n                return 1;\n            }\n            break;\n\n        case 'X':\n            if (ctrl) {\n                nk_input_key(&d3d11.ctx, NK_KEY_CUT, down);\n                return 1;\n            }\n            break;\n\n        case 'Z':\n            if (ctrl) {\n                nk_input_key(&d3d11.ctx, NK_KEY_TEXT_UNDO, down);\n                return 1;\n            }\n            break;\n\n        case 'R':\n            if (ctrl) {\n                nk_input_key(&d3d11.ctx, NK_KEY_TEXT_REDO, down);\n                return 1;\n            }\n            break;\n        }\n        return 0;\n    }\n\n    case WM_CHAR:\n        if (wparam >= 32)\n        {\n            nk_input_unicode(&d3d11.ctx, (nk_rune)wparam);\n            return 1;\n        }\n        break;\n\n    case WM_LBUTTONDOWN:\n        nk_input_button(&d3d11.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_LBUTTONUP:\n        nk_input_button(&d3d11.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        nk_input_button(&d3d11.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_RBUTTONDOWN:\n        nk_input_button(&d3d11.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_RBUTTONUP:\n        nk_input_button(&d3d11.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_MBUTTONDOWN:\n        nk_input_button(&d3d11.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_MBUTTONUP:\n        nk_input_button(&d3d11.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_XBUTTONDOWN:\n        switch (GET_XBUTTON_WPARAM(wparam)) {\n        case XBUTTON1:\n            nk_input_button(&d3d11.ctx, NK_BUTTON_X1, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n            break;\n        case XBUTTON2:\n            nk_input_button(&d3d11.ctx, NK_BUTTON_X2, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n            break;\n        }\n        SetCapture(wnd);\n        return 1;\n\n    case WM_XBUTTONUP:\n        switch (GET_XBUTTON_WPARAM(wparam)) {\n        case XBUTTON1:\n            nk_input_button(&d3d11.ctx, NK_BUTTON_X1, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n            break;\n        case XBUTTON2:\n            nk_input_button(&d3d11.ctx, NK_BUTTON_X2, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n            break;\n        }\n        ReleaseCapture();\n        return 1;\n\n    case WM_MOUSEWHEEL:\n        nk_input_scroll(&d3d11.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));\n        return 1;\n\n    case WM_MOUSEMOVE:\n        nk_input_motion(&d3d11.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));\n        return 1;\n\n    case WM_LBUTTONDBLCLK:\n        nk_input_button(&d3d11.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        return 1;\n    }\n\n    return 0;\n}\n\nstatic void\nnk_d3d11_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    (void)usr;\n    if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))\n    {\n        HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);\n        if (mem)\n        {\n            SIZE_T size = GlobalSize(mem) - 1;\n            if (size)\n            {\n                LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);\n                if (wstr)\n                {\n                    int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), NULL, 0, NULL, NULL);\n                    if (utf8size)\n                    {\n                        char* utf8 = (char*)malloc(utf8size);\n                        if (utf8)\n                        {\n                            WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), utf8, utf8size, NULL, NULL);\n                            nk_textedit_paste(edit, utf8, utf8size);\n                            free(utf8);\n                        }\n                    }\n                    GlobalUnlock(mem);\n                }\n            }\n        }\n        CloseClipboard();\n    }\n}\n\nstatic void\nnk_d3d11_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    (void)usr;\n    if (OpenClipboard(NULL))\n    {\n        int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);\n        if (wsize)\n        {\n            HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));\n            if (mem)\n            {\n                wchar_t* wstr = (wchar_t*)GlobalLock(mem);\n                if (wstr)\n                {\n                    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);\n                    wstr[wsize] = 0;\n                    GlobalUnlock(mem);\n                    SetClipboardData(CF_UNICODETEXT, mem);\n                }\n            }\n        }\n        CloseClipboard();\n    }\n}\n\nNK_API struct nk_context*\nnk_d3d11_init(ID3D11Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer)\n{\n    HRESULT hr;\n    d3d11.max_vertex_buffer = max_vertex_buffer;\n    d3d11.max_index_buffer = max_index_buffer;\n    d3d11.device = device;\n    ID3D11Device_AddRef(device);\n\n    nk_init_default(&d3d11.ctx, 0);\n    d3d11.ctx.clip.copy = nk_d3d11_clipboard_copy;\n    d3d11.ctx.clip.paste = nk_d3d11_clipboard_paste;\n    d3d11.ctx.clip.userdata = nk_handle_ptr(0);\n\n    nk_buffer_init_default(&d3d11.cmds);\n\n    {/* rasterizer state */\n    D3D11_RASTERIZER_DESC desc;\n    memset(&desc, 0, sizeof(desc));\n    desc.FillMode = D3D11_FILL_SOLID;\n    desc.CullMode = D3D11_CULL_NONE;\n    desc.FrontCounterClockwise = FALSE;\n    desc.DepthBias = 0;\n    desc.DepthBiasClamp = 0;\n    desc.SlopeScaledDepthBias = 0.0f;\n    desc.DepthClipEnable = TRUE;\n    desc.ScissorEnable = TRUE;\n    desc.MultisampleEnable = FALSE;\n    desc.AntialiasedLineEnable = FALSE;\n    hr = ID3D11Device_CreateRasterizerState(device,&desc, &d3d11.rasterizer_state);\n    NK_ASSERT(SUCCEEDED(hr));}\n\n    /* vertex shader */\n    {hr = ID3D11Device_CreateVertexShader(device,nk_d3d11_vertex_shader, sizeof(nk_d3d11_vertex_shader), NULL, &d3d11.vertex_shader);\n    NK_ASSERT(SUCCEEDED(hr));}\n\n    /* input layout */\n    {const D3D11_INPUT_ELEMENT_DESC layout[] = {\n        { \"POSITION\", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(struct nk_d3d11_vertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 },\n        { \"TEXCOORD\", 0, DXGI_FORMAT_R32G32_FLOAT,       0, offsetof(struct nk_d3d11_vertex, uv),       D3D11_INPUT_PER_VERTEX_DATA, 0 },\n        { \"COLOR\",    0, DXGI_FORMAT_R8G8B8A8_UNORM,     0, offsetof(struct nk_d3d11_vertex, col),      D3D11_INPUT_PER_VERTEX_DATA, 0 },\n    };\n    hr = ID3D11Device_CreateInputLayout(device,layout, ARRAYSIZE(layout), nk_d3d11_vertex_shader, sizeof(nk_d3d11_vertex_shader), &d3d11.input_layout);\n    NK_ASSERT(SUCCEEDED(hr));}\n\n    /* constant buffer */\n    {float matrix[4*4];\n    D3D11_BUFFER_DESC desc;\n    memset(&desc, 0, sizeof(desc));\n    desc.ByteWidth = sizeof(matrix);\n    desc.Usage = D3D11_USAGE_DYNAMIC;\n    desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;\n    desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;\n    desc.MiscFlags = 0;\n\n    {D3D11_SUBRESOURCE_DATA data;\n    data.pSysMem = matrix;\n    data.SysMemPitch = 0;\n    data.SysMemSlicePitch = 0;\n\n    nk_d3d11_get_projection_matrix(width, height, matrix);\n    hr = ID3D11Device_CreateBuffer(device, &desc, &data, &d3d11.const_buffer);\n    NK_ASSERT(SUCCEEDED(hr));}}\n\n    /* pixel shader */\n    {hr = ID3D11Device_CreatePixelShader(device, nk_d3d11_pixel_shader, sizeof(nk_d3d11_pixel_shader), NULL, &d3d11.pixel_shader);\n    NK_ASSERT(SUCCEEDED(hr));}\n\n    {/* blend state */\n    D3D11_BLEND_DESC desc;\n    memset(&desc, 0, sizeof(desc));\n    desc.AlphaToCoverageEnable = FALSE;\n    desc.RenderTarget[0].BlendEnable = TRUE;\n    desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;\n    desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;\n    desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;\n    desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;\n    desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;\n    desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;\n    desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;\n    hr = ID3D11Device_CreateBlendState(device, &desc, &d3d11.blend_state);\n    NK_ASSERT(SUCCEEDED(hr));}\n\n    /* vertex buffer */\n    {D3D11_BUFFER_DESC desc;\n    memset(&desc, 0, sizeof(desc));\n    desc.Usage = D3D11_USAGE_DYNAMIC;\n    desc.ByteWidth = max_vertex_buffer;\n    desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;\n    desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;\n    desc.MiscFlags = 0;\n    hr = ID3D11Device_CreateBuffer(device, &desc, NULL, &d3d11.vertex_buffer);\n    NK_ASSERT(SUCCEEDED(hr));}\n\n    /* index buffer */\n    {D3D11_BUFFER_DESC desc;\n    memset(&desc, 0, sizeof(desc));\n    desc.Usage = D3D11_USAGE_DYNAMIC;\n    desc.ByteWidth = max_index_buffer;\n    desc.BindFlags = D3D11_BIND_INDEX_BUFFER;\n    desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;\n    hr = ID3D11Device_CreateBuffer(device, &desc, NULL, &d3d11.index_buffer);\n    NK_ASSERT(SUCCEEDED(hr));}\n\n    /* sampler state */\n    {D3D11_SAMPLER_DESC desc;\n    memset(&desc, 0, sizeof(desc));\n    desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;\n    desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;\n    desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;\n    desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;\n    desc.MipLODBias = 0.0f;\n    desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;\n    desc.MinLOD = 0.0f;\n    desc.MaxLOD = FLT_MAX;\n    hr = ID3D11Device_CreateSamplerState(device, &desc, &d3d11.sampler_state);\n    NK_ASSERT(SUCCEEDED(hr));}\n\n    /* viewport */\n    {d3d11.viewport.TopLeftX = 0.0f;\n    d3d11.viewport.TopLeftY = 0.0f;\n    d3d11.viewport.Width = (float)width;\n    d3d11.viewport.Height = (float)height;\n    d3d11.viewport.MinDepth = 0.0f;\n    d3d11.viewport.MaxDepth = 1.0f;}\n    return &d3d11.ctx;\n}\n\nNK_API void\nnk_d3d11_font_stash_begin(struct nk_font_atlas **atlas)\n{\n    nk_font_atlas_init_default(&d3d11.atlas);\n    nk_font_atlas_begin(&d3d11.atlas);\n    *atlas = &d3d11.atlas;\n}\n\nNK_API void\nnk_d3d11_font_stash_end(void)\n{\n    const void *image; int w, h;\n    image = nk_font_atlas_bake(&d3d11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n\n    /* upload font to texture and create texture view */\n    {ID3D11Texture2D *font_texture;\n    HRESULT hr;\n\n    D3D11_TEXTURE2D_DESC desc;\n    memset(&desc, 0, sizeof(desc));\n    desc.Width = (UINT)w;\n    desc.Height = (UINT)h;\n    desc.MipLevels = 1;\n    desc.ArraySize = 1;\n    desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n    desc.SampleDesc.Count = 1;\n    desc.SampleDesc.Quality = 0;\n    desc.Usage = D3D11_USAGE_DEFAULT;\n    desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;\n    desc.CPUAccessFlags = 0;\n\n    {D3D11_SUBRESOURCE_DATA data;\n    data.pSysMem = image;\n    data.SysMemPitch = (UINT)(w * 4);\n    data.SysMemSlicePitch = 0;\n    hr = ID3D11Device_CreateTexture2D(d3d11.device, &desc, &data, &font_texture);\n    assert(SUCCEEDED(hr));}\n\n    {D3D11_SHADER_RESOURCE_VIEW_DESC srv;\n    memset(&srv, 0, sizeof(srv));\n    srv.Format = desc.Format;\n    srv.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;\n    srv.Texture2D.MipLevels = 1;\n    srv.Texture2D.MostDetailedMip = 0;\n    hr = ID3D11Device_CreateShaderResourceView(d3d11.device, (ID3D11Resource *)font_texture, &srv, &d3d11.font_texture_view);\n    assert(SUCCEEDED(hr));}\n    ID3D11Texture2D_Release(font_texture);}\n\n    nk_font_atlas_end(&d3d11.atlas, nk_handle_ptr(d3d11.font_texture_view), &d3d11.tex_null);\n    if (d3d11.atlas.default_font)\n        nk_style_set_font(&d3d11.ctx, &d3d11.atlas.default_font->handle);\n}\n\nNK_API\nvoid nk_d3d11_shutdown(void)\n{\n    nk_font_atlas_clear(&d3d11.atlas);\n    nk_buffer_free(&d3d11.cmds);\n    nk_free(&d3d11.ctx);\n\n    ID3D11SamplerState_Release(d3d11.sampler_state);\n    ID3D11ShaderResourceView_Release(d3d11.font_texture_view);\n    ID3D11Buffer_Release(d3d11.vertex_buffer);\n    ID3D11Buffer_Release(d3d11.index_buffer);\n    ID3D11BlendState_Release(d3d11.blend_state);\n    ID3D11PixelShader_Release(d3d11.pixel_shader);\n    ID3D11Buffer_Release(d3d11.const_buffer);\n    ID3D11VertexShader_Release(d3d11.vertex_shader);\n    ID3D11InputLayout_Release(d3d11.input_layout);\n    ID3D11RasterizerState_Release(d3d11.rasterizer_state);\n    ID3D11Device_Release(d3d11.device);\n}\n\n#endif\n\n"
  },
  {
    "path": "demo/d3d11/nuklear_d3d11.hlsl",
    "content": "//\ncbuffer buffer0 : register(b0)\n{\n  float4x4 ProjectionMatrix;\n};\n\nsampler sampler0 : register(s0);\nTexture2D<float4> texture0 : register(t0);\n\nstruct VS_INPUT\n{\n  float2 pos : POSITION;\n  float4 col : COLOR0;\n  float2 uv  : TEXCOORD0;\n};\n\nstruct PS_INPUT\n{\n  float4 pos : SV_POSITION;\n  float4 col : COLOR0;\n  float2 uv  : TEXCOORD0;\n};\n\nPS_INPUT vs(VS_INPUT input)\n{\n  PS_INPUT output;\n  output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\n  output.col = input.col;\n  output.uv  = input.uv;\n  return output;\n}\n\nfloat4 ps(PS_INPUT input) : SV_Target\n{\n  return input.col * texture0.Sample(sampler0, input.uv);\n}\n"
  },
  {
    "path": "demo/d3d11/nuklear_d3d11_pixel_shader.h",
    "content": "#if 0\n//\n// Generated by Microsoft (R) D3D Shader Disassembler\n//\n//\n// Input signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// SV_POSITION              0   xyzw        0      POS   float       \n// COLOR                    0   xyzw        1     NONE   float   xyzw\n// TEXCOORD                 0   xy          2     NONE   float   xy  \n//\n//\n// Output signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// SV_Target                0   xyzw        0   TARGET   float   xyzw\n//\n//\n// Sampler/Resource to DX9 shader sampler mappings:\n//\n// Target Sampler Source Sampler  Source Resource\n// -------------- --------------- ----------------\n// s0             s0              t0               \n//\n//\n// Level9 shader bytecode:\n//\n    ps_2_0\n    dcl t0\n    dcl t1.xy\n    dcl_2d s0\n    texld r0, t1, s0\n    mul r0, r0, t0\n    mov oC0, r0\n\n// approximately 3 instruction slots used (1 texture, 2 arithmetic)\n//\n// Sampler/Resource to DX9 shader sampler mappings:\n//\n// Target Sampler Source Sampler  Source Resource\n// -------------- --------------- ----------------\n// s0             s0              t0               \n//\n//\n// XNA shader bytecode:\n//\n    ps_2_0\n    dcl t0\n    dcl t1.xy\n    dcl_2d s0\n    texld r0, r2, s0\n    mul oC0, r0, r1\n\n// approximately 2 instruction slots used (1 texture, 1 arithmetic)\nps_4_0\ndcl_sampler s0, mode_default\ndcl_resource_texture2d (float,float,float,float) t0\ndcl_input_ps linear v1.xyzw\ndcl_input_ps linear v2.xy\ndcl_output o0.xyzw\ndcl_temps 1\nsample r0.xyzw, v2.xyxx, t0.xyzw, s0\nmul o0.xyzw, r0.xyzw, v1.xyzw\nret \n// Approximately 0 instruction slots used\n#endif\n\nconst BYTE nk_d3d11_pixel_shader[] =\n{\n     68,  88,  66,  67, 249,  46, \n     26,  75, 111, 182, 161, 241, \n    199, 179, 191,  89,  44, 229, \n    245, 103,   1,   0,   0,   0, \n    124,   2,   0,   0,   5,   0, \n      0,   0,  52,   0,   0,   0, \n    176,   0,   0,   0,  56,   1, \n      0,   0, 212,   1,   0,   0, \n     72,   2,   0,   0,  88,  78, \n     65,  83, 116,   0,   0,   0, \n    116,   0,   0,   0,   0,   2, \n    255, 255,  76,   0,   0,   0, \n     40,   0,   0,   0,   0,   0, \n     40,   0,   0,   0,  40,   0, \n      0,   0,  40,   0,   1,   0, \n     36,   0,   0,   0,  40,   0, \n      0,   0,   0,   0,   0,   2, \n    255, 255,  31,   0,   0,   2, \n      0,   0,   0, 128,   0,   0, \n     15, 176,  31,   0,   0,   2, \n      0,   0,   0, 128,   1,   0, \n      3, 176,  31,   0,   0,   2, \n      0,   0,   0, 144,   0,   8, \n     15, 160,  66,   0,   0,   3, \n      0,   0,  15, 128,   2,   0, \n    228, 128,   0,   8, 228, 160, \n      5,   0,   0,   3,   0,   8, \n     15, 128,   0,   0, 228, 128, \n      1,   0, 228, 128, 255, 255, \n      0,   0,  65, 111, 110,  57, \n    128,   0,   0,   0, 128,   0, \n      0,   0,   0,   2, 255, 255, \n     88,   0,   0,   0,  40,   0, \n      0,   0,   0,   0,  40,   0, \n      0,   0,  40,   0,   0,   0, \n     40,   0,   1,   0,  36,   0, \n      0,   0,  40,   0,   0,   0, \n      0,   0,   0,   2, 255, 255, \n     31,   0,   0,   2,   0,   0, \n      0, 128,   0,   0,  15, 176, \n     31,   0,   0,   2,   0,   0, \n      0, 128,   1,   0,   3, 176, \n     31,   0,   0,   2,   0,   0, \n      0, 144,   0,   8,  15, 160, \n     66,   0,   0,   3,   0,   0, \n     15, 128,   1,   0, 228, 176, \n      0,   8, 228, 160,   5,   0, \n      0,   3,   0,   0,  15, 128, \n      0,   0, 228, 128,   0,   0, \n    228, 176,   1,   0,   0,   2, \n      0,   8,  15, 128,   0,   0, \n    228, 128, 255, 255,   0,   0, \n     83,  72,  68,  82, 148,   0, \n      0,   0,  64,   0,   0,   0, \n     37,   0,   0,   0,  90,   0, \n      0,   3,   0,  96,  16,   0, \n      0,   0,   0,   0,  88,  24, \n      0,   4,   0, 112,  16,   0, \n      0,   0,   0,   0,  85,  85, \n      0,   0,  98,  16,   0,   3, \n    242,  16,  16,   0,   1,   0, \n      0,   0,  98,  16,   0,   3, \n     50,  16,  16,   0,   2,   0, \n      0,   0, 101,   0,   0,   3, \n    242,  32,  16,   0,   0,   0, \n      0,   0, 104,   0,   0,   2, \n      1,   0,   0,   0,  69,   0, \n      0,   9, 242,   0,  16,   0, \n      0,   0,   0,   0,  70,  16, \n     16,   0,   2,   0,   0,   0, \n     70, 126,  16,   0,   0,   0, \n      0,   0,   0,  96,  16,   0, \n      0,   0,   0,   0,  56,   0, \n      0,   7, 242,  32,  16,   0, \n      0,   0,   0,   0,  70,  14, \n     16,   0,   0,   0,   0,   0, \n     70,  30,  16,   0,   1,   0, \n      0,   0,  62,   0,   0,   1, \n     73,  83,  71,  78, 108,   0, \n      0,   0,   3,   0,   0,   0, \n      8,   0,   0,   0,  80,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,  92,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   1,   0,   0,   0, \n     15,  15,   0,   0,  98,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   2,   0,   0,   0, \n      3,   3,   0,   0,  83,  86, \n     95,  80,  79,  83,  73,  84, \n     73,  79,  78,   0,  67,  79, \n     76,  79,  82,   0,  84,  69, \n     88,  67,  79,  79,  82,  68, \n      0, 171,  79,  83,  71,  78, \n     44,   0,   0,   0,   1,   0, \n      0,   0,   8,   0,   0,   0, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n     83,  86,  95,  84,  97, 114, \n    103, 101, 116,   0, 171, 171\n};\n"
  },
  {
    "path": "demo/d3d11/nuklear_d3d11_vertex_shader.h",
    "content": "#if 0\n//\n// Generated by Microsoft (R) D3D Shader Disassembler\n//\n//\n// Input signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// POSITION                 0   xy          0     NONE   float   xy  \n// COLOR                    0   xyzw        1     NONE   float   xyzw\n// TEXCOORD                 0   xy          2     NONE   float   xy  \n//\n//\n// Output signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// SV_POSITION              0   xyzw        0      POS   float   xyzw\n// COLOR                    0   xyzw        1     NONE   float   xyzw\n// TEXCOORD                 0   xy          2     NONE   float   xy  \n//\n//\n// Constant buffer to DX9 shader constant mappings:\n//\n// Target Reg Buffer  Start Reg # of Regs        Data Conversion\n// ---------- ------- --------- --------- ----------------------\n// c1         cb0             0         4  ( FLT, FLT, FLT, FLT)\n//\n//\n// Runtime generated constant mappings:\n//\n// Target Reg                               Constant Description\n// ---------- --------------------------------------------------\n// c0                              Vertex Shader position offset\n//\n//\n// Level9 shader bytecode:\n//\n    vs_2_0\n    def c5, 0, 1, 0, 0\n    dcl_texcoord v0\n    dcl_texcoord1 v1\n    dcl_texcoord2 v2\n    mul r0, v0.x, c1\n    mad r0, c2, v0.y, r0\n    mov r1.xy, c5\n    mad r0, c3, r1.x, r0\n    mad r0, c4, r1.y, r0\n    mul r1.xy, r0.w, c0\n    add oPos.xy, r0, r1\n    mov oPos.zw, r0\n    mov oT0, v1\n    mov oT1.xy, v2\n\n// approximately 10 instruction slots used\n//\n// Constant buffer to DX9 shader constant mappings:\n//\n// Target Reg Buffer  Start Reg # of Regs        Data Conversion\n// ---------- ------- --------- --------- ----------------------\n// c0         cb0             0         4  ( FLT, FLT, FLT, FLT)\n//\n//\n// XNA Prepass shader bytecode:\n//\n    vs_2_0\n    def c4, 0, 1, 0, 0\n    dcl_texcoord v0\n    mul r1, r0.x, c0\n    mad r0, c1, r0.y, r1\n    mov r1.xy, c4\n    mad r0, c2, r1.x, r0\n    mad r0, c3, r1.y, r0\n    mov oPos, r0\n\n// approximately 6 instruction slots used\n//\n// Constant buffer to DX9 shader constant mappings:\n//\n// Target Reg Buffer  Start Reg # of Regs        Data Conversion\n// ---------- ------- --------- --------- ----------------------\n// c0         cb0             0         4  ( FLT, FLT, FLT, FLT)\n//\n//\n// XNA shader bytecode:\n//\n    vs_2_0\n    def c4, 0, 1, 0, 0\n    dcl_texcoord v0\n    dcl_texcoord1 v1\n    dcl_texcoord2 v2\n    mov oT0, r1\n    mov oT1.xy, r2\n    mul r1, r0.x, c0\n    mad r0, c1, r0.y, r1\n    mov r1.xy, c4\n    mad r0, c2, r1.x, r0\n    mad r0, c3, r1.y, r0\n    mov oPos, r0\n\n// approximately 8 instruction slots used\nvs_4_0\ndcl_constantbuffer cb0[4], immediateIndexed\ndcl_input v0.xy\ndcl_input v1.xyzw\ndcl_input v2.xy\ndcl_output_siv o0.xyzw, position\ndcl_output o1.xyzw\ndcl_output o2.xy\ndcl_temps 1\nmul r0.xyzw, v0.xxxx, cb0[0].xyzw\nmad r0.xyzw, cb0[1].xyzw, v0.yyyy, r0.xyzw\nmad r0.xyzw, cb0[2].xyzw, l(0.000000, 0.000000, 0.000000, 0.000000), r0.xyzw\nmad o0.xyzw, cb0[3].xyzw, l(1.000000, 1.000000, 1.000000, 1.000000), r0.xyzw\nmov o1.xyzw, v1.xyzw\nmov o2.xy, v2.xyxx\nret \n// Approximately 0 instruction slots used\n#endif\n\nconst BYTE nk_d3d11_vertex_shader[] =\n{\n     68,  88,  66,  67, 215, 245, \n     86, 155, 188, 117,  37, 118, \n    193, 207, 209,  90, 160, 153, \n    246, 188,   1,   0,   0,   0, \n     72,   5,   0,   0,   6,   0, \n      0,   0,  56,   0,   0,   0, \n     48,   1,   0,   0, 248,   1, \n      0,   0,  20,   3,   0,   0, \n    100,   4,   0,   0, 212,   4, \n      0,   0,  88,  78,  65,  83, \n    240,   0,   0,   0, 240,   0, \n      0,   0,   0,   2, 254, 255, \n    192,   0,   0,   0,  48,   0, \n      0,   0,   1,   0,  36,   0, \n      0,   0,  48,   0,   0,   0, \n     48,   0,   0,   0,  36,   0, \n      0,   0,  48,   0,   0,   0, \n      0,   0,   4,   0,   0,   0, \n      0,   0,   0,   0,   0,   2, \n    254, 255,  81,   0,   0,   5, \n      4,   0,  15, 160,   0,   0, \n      0,   0,   0,   0, 128,  63, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  31,   0,   0,   2, \n      5,   0,   0, 128,   0,   0, \n     15, 144,  31,   0,   0,   2, \n      5,   0,   1, 128,   1,   0, \n     15, 144,  31,   0,   0,   2, \n      5,   0,   2, 128,   2,   0, \n     15, 144,   1,   0,   0,   2, \n      0,   0,  15, 224,   1,   0, \n    228, 128,   1,   0,   0,   2, \n      1,   0,   3, 224,   2,   0, \n    228, 128,   5,   0,   0,   3, \n      1,   0,  15, 128,   0,   0, \n      0, 128,   0,   0, 228, 160, \n      4,   0,   0,   4,   0,   0, \n     15, 128,   1,   0, 228, 160, \n      0,   0,  85, 128,   1,   0, \n    228, 128,   1,   0,   0,   2, \n      1,   0,   3, 128,   4,   0, \n    228, 160,   4,   0,   0,   4, \n      0,   0,  15, 128,   2,   0, \n    228, 160,   1,   0,   0, 128, \n      0,   0, 228, 128,   4,   0, \n      0,   4,   0,   0,  15, 128, \n      3,   0, 228, 160,   1,   0, \n     85, 128,   0,   0, 228, 128, \n      1,   0,   0,   2,   0,   0, \n     15, 192,   0,   0, 228, 128, \n    255, 255,   0,   0,  88,  78, \n     65,  80, 192,   0,   0,   0, \n    192,   0,   0,   0,   0,   2, \n    254, 255, 144,   0,   0,   0, \n     48,   0,   0,   0,   1,   0, \n     36,   0,   0,   0,  48,   0, \n      0,   0,  48,   0,   0,   0, \n     36,   0,   0,   0,  48,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   2, 254, 255,  81,   0, \n      0,   5,   4,   0,  15, 160, \n      0,   0,   0,   0,   0,   0, \n    128,  63,   0,   0,   0,   0, \n      0,   0,   0,   0,  31,   0, \n      0,   2,   5,   0,   0, 128, \n      0,   0,  15, 144,   5,   0, \n      0,   3,   1,   0,  15, 128, \n      0,   0,   0, 128,   0,   0, \n    228, 160,   4,   0,   0,   4, \n      0,   0,  15, 128,   1,   0, \n    228, 160,   0,   0,  85, 128, \n      1,   0, 228, 128,   1,   0, \n      0,   2,   1,   0,   3, 128, \n      4,   0, 228, 160,   4,   0, \n      0,   4,   0,   0,  15, 128, \n      2,   0, 228, 160,   1,   0, \n      0, 128,   0,   0, 228, 128, \n      4,   0,   0,   4,   0,   0, \n     15, 128,   3,   0, 228, 160, \n      1,   0,  85, 128,   0,   0, \n    228, 128,   1,   0,   0,   2, \n      0,   0,  15, 192,   0,   0, \n    228, 128, 255, 255,   0,   0, \n     65, 111, 110,  57,  20,   1, \n      0,   0,  20,   1,   0,   0, \n      0,   2, 254, 255, 224,   0, \n      0,   0,  52,   0,   0,   0, \n      1,   0,  36,   0,   0,   0, \n     48,   0,   0,   0,  48,   0, \n      0,   0,  36,   0,   1,   0, \n     48,   0,   0,   0,   0,   0, \n      4,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   2, 254, 255,  81,   0, \n      0,   5,   5,   0,  15, 160, \n      0,   0,   0,   0,   0,   0, \n    128,  63,   0,   0,   0,   0, \n      0,   0,   0,   0,  31,   0, \n      0,   2,   5,   0,   0, 128, \n      0,   0,  15, 144,  31,   0, \n      0,   2,   5,   0,   1, 128, \n      1,   0,  15, 144,  31,   0, \n      0,   2,   5,   0,   2, 128, \n      2,   0,  15, 144,   5,   0, \n      0,   3,   0,   0,  15, 128, \n      0,   0,   0, 144,   1,   0, \n    228, 160,   4,   0,   0,   4, \n      0,   0,  15, 128,   2,   0, \n    228, 160,   0,   0,  85, 144, \n      0,   0, 228, 128,   1,   0, \n      0,   2,   1,   0,   3, 128, \n      5,   0, 228, 160,   4,   0, \n      0,   4,   0,   0,  15, 128, \n      3,   0, 228, 160,   1,   0, \n      0, 128,   0,   0, 228, 128, \n      4,   0,   0,   4,   0,   0, \n     15, 128,   4,   0, 228, 160, \n      1,   0,  85, 128,   0,   0, \n    228, 128,   5,   0,   0,   3, \n      1,   0,   3, 128,   0,   0, \n    255, 128,   0,   0, 228, 160, \n      2,   0,   0,   3,   0,   0, \n      3, 192,   0,   0, 228, 128, \n      1,   0, 228, 128,   1,   0, \n      0,   2,   0,   0,  12, 192, \n      0,   0, 228, 128,   1,   0, \n      0,   2,   0,   0,  15, 224, \n      1,   0, 228, 144,   1,   0, \n      0,   2,   1,   0,   3, 224, \n      2,   0, 228, 144, 255, 255, \n      0,   0,  83,  72,  68,  82, \n     72,   1,   0,   0,  64,   0, \n      1,   0,  82,   0,   0,   0, \n     89,   0,   0,   4,  70, 142, \n     32,   0,   0,   0,   0,   0, \n      4,   0,   0,   0,  95,   0, \n      0,   3,  50,  16,  16,   0, \n      0,   0,   0,   0,  95,   0, \n      0,   3, 242,  16,  16,   0, \n      1,   0,   0,   0,  95,   0, \n      0,   3,  50,  16,  16,   0, \n      2,   0,   0,   0, 103,   0, \n      0,   4, 242,  32,  16,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0, 101,   0,   0,   3, \n    242,  32,  16,   0,   1,   0, \n      0,   0, 101,   0,   0,   3, \n     50,  32,  16,   0,   2,   0, \n      0,   0, 104,   0,   0,   2, \n      1,   0,   0,   0,  56,   0, \n      0,   8, 242,   0,  16,   0, \n      0,   0,   0,   0,   6,  16, \n     16,   0,   0,   0,   0,   0, \n     70, 142,  32,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     50,   0,   0,  10, 242,   0, \n     16,   0,   0,   0,   0,   0, \n     70, 142,  32,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     86,  21,  16,   0,   0,   0, \n      0,   0,  70,  14,  16,   0, \n      0,   0,   0,   0,  50,   0, \n      0,  13, 242,   0,  16,   0, \n      0,   0,   0,   0,  70, 142, \n     32,   0,   0,   0,   0,   0, \n      2,   0,   0,   0,   2,  64, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     70,  14,  16,   0,   0,   0, \n      0,   0,  50,   0,   0,  13, \n    242,  32,  16,   0,   0,   0, \n      0,   0,  70, 142,  32,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   2,  64,   0,   0, \n      0,   0, 128,  63,   0,   0, \n    128,  63,   0,   0, 128,  63, \n      0,   0, 128,  63,  70,  14, \n     16,   0,   0,   0,   0,   0, \n     54,   0,   0,   5, 242,  32, \n     16,   0,   1,   0,   0,   0, \n     70,  30,  16,   0,   1,   0, \n      0,   0,  54,   0,   0,   5, \n     50,  32,  16,   0,   2,   0, \n      0,   0,  70,  16,  16,   0, \n      2,   0,   0,   0,  62,   0, \n      0,   1,  73,  83,  71,  78, \n    104,   0,   0,   0,   3,   0, \n      0,   0,   8,   0,   0,   0, \n     80,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,   3,   3,   0,   0, \n     89,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   1,   0, \n      0,   0,  15,  15,   0,   0, \n     95,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   2,   0, \n      0,   0,   3,   3,   0,   0, \n     80,  79,  83,  73,  84,  73, \n     79,  78,   0,  67,  79,  76, \n     79,  82,   0,  84,  69,  88, \n     67,  79,  79,  82,  68,   0, \n     79,  83,  71,  78, 108,   0, \n      0,   0,   3,   0,   0,   0, \n      8,   0,   0,   0,  80,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,  92,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   1,   0,   0,   0, \n     15,   0,   0,   0,  98,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   2,   0,   0,   0, \n      3,  12,   0,   0,  83,  86, \n     95,  80,  79,  83,  73,  84, \n     73,  79,  78,   0,  67,  79, \n     76,  79,  82,   0,  84,  69, \n     88,  67,  79,  79,  82,  68, \n      0, 171\n};\n"
  },
  {
    "path": "demo/d3d12/build.bat",
    "content": "@echo off\n\nrem This will use VS2015 for compiler... if you have vs 2015 and it is installed at this / the default path\ncall \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat\" x86\n\nfxc.exe /nologo /T vs_5_1 /E vs /O3 /Zpc /Ges /Fh nuklear_d3d12_vertex_shader.h /Vn nk_d3d12_vertex_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv nuklear_d3d12.hlsl\nfxc.exe /nologo /T ps_5_1 /E ps /O3 /Zpc /Ges /Fh nuklear_d3d12_pixel_shader.h /Vn nk_d3d12_pixel_shader /Qstrip_reflect /Qstrip_debug /Qstrip_priv /enable_unbounded_descriptor_tables nuklear_d3d12.hlsl\n\ncl /D_CRT_SECURE_NO_DEPRECATE /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib dxguid.lib dxgi.lib d3d12.lib /link /incremental:no\n"
  },
  {
    "path": "demo/d3d12/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n\n/*\n *   === IMPORTATE NOTE FOR D3D12 ===  \n *\n * Due to a bug in the Windows SDK that\n * was fixed in version 10.0.22000.0 the\n * D3D12 Backend requires this version as\n * a minimum! Compiling with a lower version\n * will result in compiler warnings and a\n * crashing application!\n * \n */\n\n#define COBJMACROS\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <combaseapi.h>\n#include <dxgi1_6.h>\n#include <d3d12.h>\n#include <stdio.h>\n#include <string.h>\n#include <limits.h>\n#include <time.h>\n\n#define WINDOW_WIDTH 800\n#define WINDOW_HEIGHT 600\n#define USER_TEXTURES 6\n\n#define MAX_VERTEX_BUFFER 512 * 1024\n#define MAX_INDEX_BUFFER 128 * 1024\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_D3D12_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_d3d12.h\"\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\n/* DXGI & Window related device objects */\nstatic IDXGIFactory2 *dxgi_factory;\nstatic IDXGISwapChain1 *swap_chain;\nstatic ID3D12DescriptorHeap *rtv_descriptor_heap;\nstatic D3D12_CPU_DESCRIPTOR_HANDLE rtv_handles[2];\nstatic ID3D12Resource *rtv_buffers[2];\nstatic UINT rtv_desc_increment;\nstatic UINT rtv_index;\n/* DirectX common device objects */\nstatic ID3D12Device *device;\nstatic ID3D12CommandQueue *command_queue;\nstatic ID3D12Fence *queue_fence;\nstatic UINT64 fence_value;\nstatic ID3D12CommandAllocator *command_allocator;\nstatic ID3D12GraphicsCommandList *command_list;\n\nstatic void signal_and_wait()\n{\n    HRESULT hr;\n\n    /* Signal fence when execution finishes */\n    hr = ID3D12CommandQueue_Signal(command_queue, queue_fence, ++fence_value);\n    assert(SUCCEEDED(hr));\n\n    /* Wait for queue to finish */\n    while(ID3D12Fence_GetCompletedValue(queue_fence) != fence_value)\n    {\n      SwitchToThread(); /* Allow windows to do other work */\n    }\n}\n\nstatic void execute_commands()\n{\n    /* Prepare command list for execution */\n    ID3D12GraphicsCommandList_Close(command_list);\n\n    /* Execute on command queue */\n    ID3D12CommandList* cmd_lists[] = { (ID3D12CommandList*)command_list};\n    ID3D12CommandQueue_ExecuteCommandLists(command_queue, 1, cmd_lists);\n\n    /* Wait for execution */\n    signal_and_wait();\n\n    /* Reset command allocator and list */\n    ID3D12CommandAllocator_Reset(command_allocator);\n    ID3D12GraphicsCommandList_Reset(command_list, command_allocator, NULL);\n}\n\nstatic void get_swap_chain_buffers()\n{\n    HRESULT hr;\n    D3D12_CPU_DESCRIPTOR_HANDLE descriptor_handle;\n\n    /* Get resource objects from swap chain */\n    hr = IDXGISwapChain1_GetBuffer(swap_chain, 0, &IID_ID3D12Resource, &rtv_buffers[0]);\n    assert(SUCCEEDED(hr));\n    hr = IDXGISwapChain1_GetBuffer(swap_chain, 1, &IID_ID3D12Resource, &rtv_buffers[1]);\n    assert(SUCCEEDED(hr));\n\n    /* Recreate render target views */\n    ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(rtv_descriptor_heap, &descriptor_handle);\n    ID3D12Device_CreateRenderTargetView(device, rtv_buffers[0], NULL, descriptor_handle);\n    rtv_handles[0] = descriptor_handle;\n    descriptor_handle.ptr += rtv_desc_increment;\n    ID3D12Device_CreateRenderTargetView(device, rtv_buffers[1], NULL, descriptor_handle);\n    rtv_handles[1] = descriptor_handle;\n}\n\nstatic void\nset_swap_chain_size(int width, int height)\n{\n    HRESULT hr;\n\n    /* Wait for pending work */\n    signal_and_wait();\n    signal_and_wait(); /* Two times because we have two buffers in flight */\n\n    /* Release all open refereces to the buffers */\n    ID3D12Resource_Release(rtv_buffers[0]);\n    ID3D12Resource_Release(rtv_buffers[1]);\n\n    /* DXGI can now perform resizing */\n    hr = IDXGISwapChain1_ResizeBuffers(swap_chain, 2, width, height, DXGI_FORMAT_UNKNOWN, DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH);\n    assert(SUCCEEDED(hr));\n\n    /* Get references for the new resized buffers */\n    get_swap_chain_buffers();\n\n    /* Reset RTV index */\n    rtv_index = 0;\n}\n\nstatic LRESULT CALLBACK\nWindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)\n{\n    switch (msg)\n    {\n    case WM_DESTROY:\n        PostQuitMessage(0);\n        return 0;\n\n    case WM_SIZE:\n        if (swap_chain)\n        {\n            int width = LOWORD(lparam);\n            int height = HIWORD(lparam);\n            set_swap_chain_size(width, height);\n            nk_d3d12_resize(width, height);\n        }\n        break;\n    }\n\n    if (nk_d3d12_handle_event(wnd, msg, wparam, lparam))\n        return 0;\n\n    return DefWindowProcW(wnd, msg, wparam, lparam);\n}\n\nint main(void)\n{\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n\n    WNDCLASSW wc;\n    RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };\n    DWORD style = WS_OVERLAPPEDWINDOW;\n    DWORD exstyle = WS_EX_APPWINDOW;\n    HWND wnd;\n    int running = 1;\n    HRESULT hr;\n\n    D3D12_COMMAND_QUEUE_DESC command_queue_desc;\n    DXGI_SWAP_CHAIN_DESC1 swap_chain_desc;\n    D3D12_DESCRIPTOR_HEAP_DESC rtv_desc_heap_desc;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    /* Win32 */\n    memset(&wc, 0, sizeof(wc));\n    wc.style = CS_DBLCLKS;\n    wc.lpfnWndProc = WindowProc;\n    wc.hInstance = GetModuleHandleW(0);\n    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);\n    wc.hCursor = LoadCursor(NULL, IDC_ARROW);\n    wc.lpszClassName = L\"NuklearWindowClass\";\n    RegisterClassW(&wc);\n\n    AdjustWindowRectEx(&rect, style, FALSE, exstyle);\n\n    wnd = CreateWindowExW(exstyle, wc.lpszClassName, L\"Nuklear Direct3D 12 Demo\",\n        style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,\n        rect.right - rect.left, rect.bottom - rect.top,\n        NULL, NULL, wc.hInstance, NULL);\n\n    /* D3D12 setup */\n    /* Create default Device */\n    hr = D3D12CreateDevice(NULL, D3D_FEATURE_LEVEL_11_0, &IID_ID3D12Device, &device);\n    assert(SUCCEEDED(hr));\n    /* Create a command queue */\n    command_queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;\n    command_queue_desc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;\n    command_queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;\n    command_queue_desc.NodeMask = 0;\n    hr = ID3D12Device_CreateCommandQueue(device, &command_queue_desc, &IID_ID3D12CommandQueue, &command_queue);\n    assert(SUCCEEDED(hr));\n    /* Create a fence for command queue executions */\n    fence_value = 0;\n    hr = ID3D12Device_CreateFence(device, fence_value, D3D12_FENCE_FLAG_NONE, &IID_ID3D12Fence, &queue_fence);\n    assert(SUCCEEDED(hr));\n    /* Create a command allocator */\n    hr = ID3D12Device_CreateCommandAllocator(device, D3D12_COMMAND_LIST_TYPE_DIRECT, &IID_ID3D12CommandAllocator, &command_allocator);\n    assert(SUCCEEDED(hr));\n    /* Create a command list that will use our allocator */\n    hr = ID3D12Device_CreateCommandList(device, 0, D3D12_COMMAND_LIST_TYPE_DIRECT, command_allocator, NULL,  &IID_ID3D12GraphicsCommandList1, &command_list);\n    assert(SUCCEEDED(hr));\n\n    /* DXGI Setup (Swap chain & resources) */\n    /* Create a descriptor heap for the back buffers */\n    rtv_desc_heap_desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;\n    rtv_desc_heap_desc.NumDescriptors = 2;\n    rtv_desc_heap_desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;\n    rtv_desc_heap_desc.NodeMask = 0;\n    hr = ID3D12Device_CreateDescriptorHeap(device, &rtv_desc_heap_desc, &IID_ID3D12DescriptorHeap, &rtv_descriptor_heap);\n    assert(SUCCEEDED(hr));\n    /* Get descriptor increment */\n    rtv_desc_increment = ID3D12Device_GetDescriptorHandleIncrementSize(device, D3D12_DESCRIPTOR_HEAP_TYPE_RTV);\n    /* Get the DXGI factory */\n    hr = CreateDXGIFactory1(&IID_IDXGIFactory2, &dxgi_factory);\n    assert(SUCCEEDED(hr));\n    /* Create the swap chain */\n    swap_chain_desc.Width = WINDOW_WIDTH;\n    swap_chain_desc.Height = WINDOW_HEIGHT;\n    swap_chain_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n    swap_chain_desc.Stereo = 0;\n    swap_chain_desc.SampleDesc.Count = 1;\n    swap_chain_desc.SampleDesc.Quality = 0;\n    swap_chain_desc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;\n    swap_chain_desc.BufferCount = 2;\n    swap_chain_desc.Scaling = DXGI_SCALING_STRETCH;\n    swap_chain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL ;\n    swap_chain_desc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;\n    swap_chain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;\n    hr = IDXGIFactory2_CreateSwapChainForHwnd(dxgi_factory, (IUnknown*)command_queue, wnd, &swap_chain_desc, NULL, NULL, &swap_chain);\n    assert(SUCCEEDED(hr));\n    get_swap_chain_buffers();\n\n    /* GUI */\n    ctx = nk_d3d12_init(device, WINDOW_WIDTH, WINDOW_HEIGHT, MAX_VERTEX_BUFFER, MAX_INDEX_BUFFER, USER_TEXTURES);\n\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {\n    struct nk_font_atlas *atlas;\n    nk_d3d12_font_stash_begin(&atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, \"../../extra_font/Roboto-Regular.ttf\", 14, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_d3d12_font_stash_end(command_list);\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &droid->handle)*/;\n    }\n\n    /* Execute the command list to make sure all texture (font) data has been uploaded */\n    execute_commands();\n    /* Now we can cleanup all resources consumed by font stashing that are no longer used */\n    nk_d3d12_font_stash_cleanup();\n\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (running)\n    {\n        /* Input */\n        MSG msg;\n        nk_input_begin(ctx);\n        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))\n        {\n            if (msg.message == WM_QUIT)\n                running = 0;\n            TranslateMessage(&msg);\n            DispatchMessageW(&msg);\n        }\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 22, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Set rtv resource state */\n        D3D12_RESOURCE_BARRIER resource_barrier;\n        resource_barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n        resource_barrier.Transition.pResource = rtv_buffers[rtv_index];\n        resource_barrier.Transition.Subresource = 0;\n        resource_barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT;\n        resource_barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET;\n        resource_barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;\n        ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, &resource_barrier);\n\n        /* Clear and set the rtv */\n        ID3D12GraphicsCommandList_ClearRenderTargetView(command_list, rtv_handles[rtv_index], &bg.r, 0, NULL);\n        ID3D12GraphicsCommandList_OMSetRenderTargets(command_list, 1, &rtv_handles[rtv_index], FALSE, NULL);\n\n        /* Draw */\n        nk_d3d12_render(command_list, NK_ANTI_ALIASING_ON);\n\n        /* Bring the rtv resource back to present state */\n        resource_barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n        resource_barrier.Transition.pResource = rtv_buffers[rtv_index];\n        resource_barrier.Transition.Subresource = 0;\n        resource_barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_RENDER_TARGET;\n        resource_barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PRESENT;\n        resource_barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;\n        ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, &resource_barrier);\n\n        /* Execute command list and wait */\n        execute_commands();\n\n        /* Present frame */\n        hr = IDXGISwapChain2_Present(swap_chain, 1, 0);\n        rtv_index = (rtv_index + 1) % 2;\n        if (hr == DXGI_ERROR_DEVICE_RESET || hr == DXGI_ERROR_DEVICE_REMOVED) {\n            /* to recover from this, you'll need to recreate device and all the resources */\n            MessageBoxW(NULL, L\"D3D12 device is lost or removed!\", L\"Error\", 0);\n            break;\n        } else if (hr == DXGI_STATUS_OCCLUDED) {\n            /* window is not visible, so vsync won't work. Let's sleep a bit to reduce CPU usage */\n            Sleep(10);\n        }\n        assert(SUCCEEDED(hr));\n    }\n\n    /* Nuklear shutdown */\n    nk_d3d12_shutdown();\n\n    /* D3D12 and DXGI shutdown */\n    signal_and_wait();\n    signal_and_wait(); /* Two times because we have two buffers in flight */\n    ID3D12Resource_Release(rtv_buffers[0]);\n    ID3D12Resource_Release(rtv_buffers[1]);\n    ID3D12DescriptorHeap_Release(rtv_descriptor_heap);\n    IDXGISwapChain1_Release(swap_chain);\n    IDXGIFactory2_Release(dxgi_factory);\n    ID3D12GraphicsCommandList_Release(command_list);\n    ID3D12CommandAllocator_Release(command_allocator);\n    ID3D12CommandQueue_Release(command_queue);\n    ID3D12Fence_Release(queue_fence);\n    ID3D12Device_Release(device);\n\n    /* win32 shutdown */\n    UnregisterClassW(wc.lpszClassName, wc.hInstance);\n\n    return 0;\n}\n"
  },
  {
    "path": "demo/d3d12/nuklear_d3d12.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n *\n * D3D12 backend created by Ludwig Fuechsl (2022)\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_D3D12_H_\n#define NK_D3D12_H_\n\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n\n/*\n * USAGE:\n *    - This function will initialize a new nuklear rendering context. The context will be bound to a GLOBAL DirectX 12 rendering state.\n */\nNK_API struct nk_context *nk_d3d12_init(ID3D12Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer, unsigned int max_user_textures);\n/*\n * USAGE:\n *    - A call to this function prepares the global nuklear d3d12 backend for receiving font information’s. Use the obtained atlas pointer to load all required fonts and do all required font setup.\n */\nNK_API void nk_d3d12_font_stash_begin(struct nk_font_atlas **atlas);\n/*\n * USAGE:\n *    - Call this function after a call to nk_d3d12_font_stash_begin(...) when all fonts have been loaded and configured.\n *    - This function will place commands on the supplied ID3D12GraphicsCommandList.\n *    - This function will allocate temporary data that is required until the command list has finish executing. The temporary data can be free by calling nk_d3d12_font_stash_cleanup(...)\n */\nNK_API void nk_d3d12_font_stash_end(ID3D12GraphicsCommandList *command_list);\n/*\n * USAGE:\n *    - This function will free temporary data that was allocated by nk_d3d12_font_stash_begin(...)\n *    - Only call this function after the command list used in the nk_d3d12_font_stash_begin(...) function call has finished executing.\n *    - It is NOT required to call this function but highly recommended.\n */\nNK_API void nk_d3d12_font_stash_cleanup();\n/*\n * USAGE:\n *    - This function will setup the supplied texture (ID3D12Resource) for rendering custom images using the supplied D3D12_SHADER_RESOURCE_VIEW_DESC.\n *    - This function may override any previous calls to nk_d3d12_set_user_texture(...) while using the same index.\n *    - The returned handle can be used as texture handle to render custom images.\n *    - The caller must keep track of the state of the texture when it comes to rendering with nk_d3d12_render(...).\n */\nNK_API nk_bool nk_d3d12_set_user_texture(unsigned int index, ID3D12Resource* texture, const D3D12_SHADER_RESOURCE_VIEW_DESC* description, nk_handle* handle_out);\n/*\n * USAGE:\n *    - This function should be called within the user window proc to allow nuklear to listen to window events\n */\nNK_API int nk_d3d12_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);\n/*\n * USAGE:\n *    - A call to this function renders any previous placed nuklear draw calls and will flush all nuklear buffers for the next frame\n *    - This function will place commands on the supplied ID3D12GraphicsCommandList.\n *    - When using custom images for rendering make sure they are in the correct resource state (D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) when calling this function.\n *    - This function will upload data to the gpu (64 + max_vertex_buffer + max_index_buffer BYTES).\n */\nNK_API void nk_d3d12_render(ID3D12GraphicsCommandList *command_list, enum nk_anti_aliasing AA);\n/*\n * USAGE:\n *    - This function will notify nuklear that the framebuffer dimensions have changed.\n */\nNK_API void nk_d3d12_resize(int width, int height);\n/*\n * USAGE:\n *    - This function will free the global d3d12 rendering state.\n */\nNK_API void nk_d3d12_shutdown(void);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_D3D12_IMPLEMENTATION\n\n#define WIN32_LEAN_AND_MEAN\n#define COBJMACROS\n#include <d3d12.h>\n\n#include <stdlib.h>\n#include <stddef.h>\n#include <string.h>\n#include <float.h>\n#include <assert.h>\n\n#include \"nuklear_d3d12_vertex_shader.h\"\n#include \"nuklear_d3d12_pixel_shader.h\"\n\nstruct nk_d3d12_vertex\n{\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstatic struct\n{\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    struct nk_buffer cmds;\n\n    struct nk_draw_null_texture tex_null;\n    unsigned int max_vertex_buffer;\n    unsigned int max_index_buffer;\n    unsigned int max_user_textures;\n\n    D3D12_HEAP_PROPERTIES heap_prop_default;\n    D3D12_HEAP_PROPERTIES heap_prop_upload;\n\n    UINT cbv_srv_uav_desc_increment;\n\n    D3D12_VIEWPORT viewport;\n    ID3D12Device *device;\n    ID3D12RootSignature *root_signature;\n    ID3D12PipelineState *pipeline_state;\n    ID3D12DescriptorHeap *desc_heap;\n    ID3D12Resource *font_texture;\n    ID3D12Resource *font_upload_buffer;\n    ID3D12Resource *upload_buffer;\n    ID3D12Resource *const_buffer;\n    ID3D12Resource *index_buffer;\n    ID3D12Resource *vertex_buffer;\n\n    D3D12_CPU_DESCRIPTOR_HANDLE cpu_descriptor_handle;\n    D3D12_GPU_DESCRIPTOR_HANDLE gpu_descriptor_handle;\n    D3D12_GPU_VIRTUAL_ADDRESS gpu_vertex_buffer_address;\n    D3D12_GPU_VIRTUAL_ADDRESS gpu_index_buffer_address;\n} d3d12;\n\nNK_API void\nnk_d3d12_render(ID3D12GraphicsCommandList *command_list, enum nk_anti_aliasing AA)\n{\n    HRESULT hr;\n#ifdef NK_UINT_DRAW_INDEX\n    DXGI_FORMAT index_buffer_format = DXGI_FORMAT_R32_UINT;\n#else\n    DXGI_FORMAT index_buffer_format = DXGI_FORMAT_R16_UINT;\n#endif\n    const UINT stride = sizeof(struct nk_d3d12_vertex);\n    const struct nk_draw_command *cmd;\n    UINT offset = 0;\n    D3D12_VERTEX_BUFFER_VIEW vertex_buffer_view;\n    D3D12_INDEX_BUFFER_VIEW index_buffer_view;\n    unsigned char* ptr_data;\n    D3D12_RANGE map_range;\n    D3D12_RESOURCE_BARRIER resource_barriers[3];\n\n    /* Activate D3D12 pipeline state and config root signature */\n    ID3D12GraphicsCommandList_SetPipelineState(command_list, d3d12.pipeline_state);\n    ID3D12GraphicsCommandList_SetGraphicsRootSignature(command_list, d3d12.root_signature);\n    ID3D12GraphicsCommandList_SetDescriptorHeaps(command_list, 1, &d3d12.desc_heap);\n    ID3D12GraphicsCommandList_SetGraphicsRootDescriptorTable(command_list, 0, d3d12.gpu_descriptor_handle);\n\n    /* Configure rendering pipeline */\n    ID3D12GraphicsCommandList_IASetPrimitiveTopology(command_list, D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);\n    vertex_buffer_view.BufferLocation = d3d12.gpu_vertex_buffer_address;\n    vertex_buffer_view.SizeInBytes = d3d12.max_vertex_buffer;\n    vertex_buffer_view.StrideInBytes = stride;\n    ID3D12GraphicsCommandList_IASetVertexBuffers(command_list, 0, 1, &vertex_buffer_view);\n    index_buffer_view.BufferLocation = d3d12.gpu_index_buffer_address;\n    index_buffer_view.Format = index_buffer_format;\n    index_buffer_view.SizeInBytes = d3d12.max_index_buffer;\n    ID3D12GraphicsCommandList_IASetIndexBuffer(command_list, &index_buffer_view);\n    ID3D12GraphicsCommandList_RSSetViewports(command_list, 1, &d3d12.viewport);\n\n    /* Map upload buffer to cpu accessible pointer */\n    map_range.Begin = sizeof(float) * 4 * 4;\n    map_range.End = map_range.Begin + d3d12.max_vertex_buffer + d3d12.max_index_buffer;\n    hr = ID3D12Resource_Map(d3d12.upload_buffer, 0, &map_range, &ptr_data);\n    NK_ASSERT(SUCCEEDED(hr));\n\n    /* Nuklear convert and copy to upload buffer */\n    {\n    struct nk_convert_config config;\n    NK_STORAGE const struct nk_draw_vertex_layout_element vertex_layout[] = {\n        {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d12_vertex, position)},\n        {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_d3d12_vertex, uv)},\n        {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_d3d12_vertex, col)},\n        {NK_VERTEX_LAYOUT_END}\n    };\n    memset(&config, 0, sizeof(config));\n    config.vertex_layout = vertex_layout;\n    config.vertex_size = sizeof(struct nk_d3d12_vertex);\n    config.vertex_alignment = NK_ALIGNOF(struct nk_d3d12_vertex);\n    config.global_alpha = 1.0f;\n    config.shape_AA = AA;\n    config.line_AA = AA;\n    config.circle_segment_count = 22;\n    config.curve_segment_count = 22;\n    config.arc_segment_count = 22;\n    config.tex_null = d3d12.tex_null;\n\n    struct nk_buffer vbuf, ibuf;\n    nk_buffer_init_fixed(&vbuf, &ptr_data[sizeof(float) * 4 * 4], (size_t)d3d12.max_vertex_buffer);\n    nk_buffer_init_fixed(&ibuf, &ptr_data[sizeof(float) * 4 * 4 + d3d12.max_vertex_buffer], (size_t)d3d12.max_index_buffer);\n    nk_convert(&d3d12.ctx, &d3d12.cmds, &vbuf, &ibuf, &config);\n    }\n\n    /* Close mapping range */\n    ID3D12Resource_Unmap(d3d12.upload_buffer, 0, &map_range);\n\n    /* Issue GPU resource change for copying */\n    resource_barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n    resource_barriers[0].Transition.pResource = d3d12.const_buffer;\n    resource_barriers[0].Transition.Subresource = 0;\n    resource_barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;\n    resource_barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;\n    resource_barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;\n    resource_barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n    resource_barriers[1].Transition.pResource = d3d12.vertex_buffer;\n    resource_barriers[1].Transition.Subresource = 0;\n    resource_barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;\n    resource_barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;\n    resource_barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;\n    resource_barriers[2].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n    resource_barriers[2].Transition.pResource = d3d12.index_buffer;\n    resource_barriers[2].Transition.Subresource = 0;\n    resource_barriers[2].Transition.StateBefore = D3D12_RESOURCE_STATE_INDEX_BUFFER;\n    resource_barriers[2].Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_DEST;\n    resource_barriers[2].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;\n    ID3D12GraphicsCommandList_ResourceBarrier(command_list, 3, resource_barriers);\n\n    /* Copy from upload buffer to gpu buffers */\n    ID3D12GraphicsCommandList_CopyBufferRegion(command_list, d3d12.const_buffer, 0, d3d12.upload_buffer, 0, sizeof(float) * 4 * 4);\n    ID3D12GraphicsCommandList_CopyBufferRegion(command_list, d3d12.vertex_buffer, 0, d3d12.upload_buffer, sizeof(float) * 4 * 4, d3d12.max_vertex_buffer);\n    ID3D12GraphicsCommandList_CopyBufferRegion(command_list, d3d12.index_buffer, 0, d3d12.upload_buffer, sizeof(float) * 4 * 4 + d3d12.max_vertex_buffer, d3d12.max_index_buffer);\n\n    /* Issue GPU resource change for rendering */\n    resource_barriers[0].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n    resource_barriers[0].Transition.pResource = d3d12.const_buffer;\n    resource_barriers[0].Transition.Subresource = 0;\n    resource_barriers[0].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;\n    resource_barriers[0].Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;\n    resource_barriers[0].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;\n    resource_barriers[1].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n    resource_barriers[1].Transition.pResource = d3d12.vertex_buffer;\n    resource_barriers[1].Transition.Subresource = 0;\n    resource_barriers[1].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;\n    resource_barriers[1].Transition.StateAfter = D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER;\n    resource_barriers[1].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;\n    resource_barriers[2].Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n    resource_barriers[2].Transition.pResource = d3d12.index_buffer;\n    resource_barriers[2].Transition.Subresource = 0;\n    resource_barriers[2].Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;\n    resource_barriers[2].Transition.StateAfter = D3D12_RESOURCE_STATE_INDEX_BUFFER;\n    resource_barriers[2].Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;\n    ID3D12GraphicsCommandList_ResourceBarrier(command_list, 3, resource_barriers);\n\n    /* Issue draw commands */\n    nk_draw_foreach(cmd, &d3d12.ctx, &d3d12.cmds)\n    {\n        D3D12_RECT scissor;\n        UINT32 texture_id;\n\n        /* Only place a drawcall in case the command contains drawable data */\n        if(cmd->elem_count)\n        {\n            /* Setup scissor rect */\n            scissor.left = (LONG)cmd->clip_rect.x;\n            scissor.right = (LONG)(cmd->clip_rect.x + cmd->clip_rect.w);\n            scissor.top = (LONG)cmd->clip_rect.y;\n            scissor.bottom = (LONG)(cmd->clip_rect.y + cmd->clip_rect.h);\n            ID3D12GraphicsCommandList_RSSetScissorRects(command_list, 1, &scissor);\n\n            /* Setup texture (index to descriptor heap table) to use for draw call */\n            texture_id = (UINT32)cmd->texture.id;\n            ID3D12GraphicsCommandList_SetGraphicsRoot32BitConstants(command_list, 1, 1, &texture_id, 0);\n\n            /* Dispatch draw call */\n            ID3D12GraphicsCommandList_DrawIndexedInstanced(command_list, (UINT)cmd->elem_count, 1, offset, 0, 0);\n            offset += cmd->elem_count;\n        }\n    }\n\n    /* Default nuklear context and command buffer clear */\n    nk_clear(&d3d12.ctx);\n    nk_buffer_clear(&d3d12.cmds);\n}\n\nstatic void\nnk_d3d12_get_projection_matrix(int width, int height, float *result)\n{\n    const float L = 0.0f;\n    const float R = (float)width;\n    const float T = 0.0f;\n    const float B = (float)height;\n    float matrix[4][4] =\n    {\n        { 0.0f, 0.0f, 0.0f, 0.0f },\n        { 0.0f, 0.0f, 0.0f, 0.0f },\n        { 0.0f, 0.0f, 0.5f, 0.0f },\n        { 0.0f, 0.0f, 0.5f, 1.0f },\n    };\n    matrix[0][0] = 2.0f / (R - L);\n    matrix[1][1] = 2.0f / (T - B);\n    matrix[3][0] = (R + L) / (L - R);\n    matrix[3][1] = (T + B) / (B - T);\n    memcpy(result, matrix, sizeof(matrix));\n}\n\nNK_API void\nnk_d3d12_resize(int width, int height)\n{\n    D3D12_RANGE map_range;\n    void* ptr_data;\n\n    /* Describe area to be mapped (the upload buffer region where the constant buffer / projection matrix) lives */\n    map_range.Begin = 0;\n    map_range.End = sizeof(float) * 4 * 4;\n\n    /* Map area to cpu accassible pointer (from upload buffer) */\n    if (SUCCEEDED(ID3D12Resource_Map(d3d12.upload_buffer, 0, &map_range, &ptr_data)))\n    {\n        /* Compute projection matrix into upload buffer */\n        nk_d3d12_get_projection_matrix(width, height, (float*)ptr_data);\n        ID3D12Resource_Unmap(d3d12.upload_buffer, 0, &map_range);\n\n        /* Update internal viewport state to relect resize changes */\n        d3d12.viewport.Width = (float)width;\n        d3d12.viewport.Height = (float)height;\n    }\n\n    /*\n        NOTE:\n        When mapping and copying succeeds, the data will still be in CPU sided memory\n        copying to the GPU is done in the nk_d3d12_render function\n    */\n}\n\nNK_API int\nnk_d3d12_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)\n{\n    static int insert_toggle = 0;\n    switch (msg)\n    {\n    case WM_KEYDOWN:\n    case WM_KEYUP:\n    case WM_SYSKEYDOWN:\n    case WM_SYSKEYUP:\n    {\n        int down = !((lparam >> 31) & 1);\n        int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);\n\n        switch (wparam)\n        {\n        case VK_SHIFT:\n        case VK_LSHIFT:\n        case VK_RSHIFT:\n            nk_input_key(&d3d12.ctx, NK_KEY_SHIFT, down);\n            return 1;\n\n        case VK_DELETE:\n            nk_input_key(&d3d12.ctx, NK_KEY_DEL, down);\n            return 1;\n\n        case VK_RETURN:\n        case VK_SEPARATOR:\n            nk_input_key(&d3d12.ctx, NK_KEY_ENTER, down);\n            return 1;\n\n        case VK_TAB:\n            nk_input_key(&d3d12.ctx, NK_KEY_TAB, down);\n            return 1;\n\n        case VK_LEFT:\n            if (ctrl)\n                nk_input_key(&d3d12.ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else\n                nk_input_key(&d3d12.ctx, NK_KEY_LEFT, down);\n            return 1;\n\n        case VK_RIGHT:\n            if (ctrl)\n                nk_input_key(&d3d12.ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else\n                nk_input_key(&d3d12.ctx, NK_KEY_RIGHT, down);\n            return 1;\n\n        case VK_BACK:\n            nk_input_key(&d3d12.ctx, NK_KEY_BACKSPACE, down);\n            return 1;\n\n        case VK_HOME:\n            nk_input_key(&d3d12.ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_START, down);\n            return 1;\n\n        case VK_END:\n            nk_input_key(&d3d12.ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_END, down);\n            return 1;\n\n        case VK_NEXT:\n            nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_DOWN, down);\n            return 1;\n\n        case VK_PRIOR:\n            nk_input_key(&d3d12.ctx, NK_KEY_SCROLL_UP, down);\n            return 1;\n\n        case VK_ESCAPE:\n            nk_input_key(&d3d12.ctx, NK_KEY_TEXT_RESET_MODE, down);\n            return 1;\n\n        case VK_INSERT:\n        /* Only switch on release to avoid repeat issues\n         * kind of confusing since we have to negate it but we're already\n         * hacking it since Nuklear treats them as two separate keys rather\n         * than a single toggle state */\n            if (!down) {\n                insert_toggle = !insert_toggle;\n                if (insert_toggle) {\n                    nk_input_key(&d3d12.ctx, NK_KEY_TEXT_INSERT_MODE, !down);\n                    /* nk_input_key(&d3d12.ctx, NK_KEY_TEXT_REPLACE_MODE, down); */\n                } else {\n                    nk_input_key(&d3d12.ctx, NK_KEY_TEXT_REPLACE_MODE, !down);\n                    /* nk_input_key(&d3d12.ctx, NK_KEY_TEXT_INSERT_MODE, down); */\n                }\n            }\n            return 1;\n\n        case 'A':\n            if (ctrl) {\n                nk_input_key(&d3d12.ctx, NK_KEY_TEXT_SELECT_ALL, down);\n                return 1;\n            }\n            break;\n\n        case 'B':\n            if (ctrl) {\n                nk_input_key(&d3d12.ctx, NK_KEY_TEXT_LINE_START, down);\n                return 1;\n            }\n            break;\n\n        case 'E':\n            if (ctrl) {\n                nk_input_key(&d3d12.ctx, NK_KEY_TEXT_LINE_END, down);\n                return 1;\n            }\n            break;\n\n        case 'C':\n            if (ctrl) {\n                nk_input_key(&d3d12.ctx, NK_KEY_COPY, down);\n                return 1;\n            }\n            break;\n\n        case 'V':\n            if (ctrl) {\n                nk_input_key(&d3d12.ctx, NK_KEY_PASTE, down);\n                return 1;\n            }\n            break;\n\n        case 'X':\n            if (ctrl) {\n                nk_input_key(&d3d12.ctx, NK_KEY_CUT, down);\n                return 1;\n            }\n            break;\n\n        case 'Z':\n            if (ctrl) {\n                nk_input_key(&d3d12.ctx, NK_KEY_TEXT_UNDO, down);\n                return 1;\n            }\n            break;\n\n        case 'R':\n            if (ctrl) {\n                nk_input_key(&d3d12.ctx, NK_KEY_TEXT_REDO, down);\n                return 1;\n            }\n            break;\n        }\n        return 0;\n    }\n\n    case WM_CHAR:\n        if (wparam >= 32)\n        {\n            nk_input_unicode(&d3d12.ctx, (nk_rune)wparam);\n            return 1;\n        }\n        break;\n\n    case WM_LBUTTONDOWN:\n        nk_input_button(&d3d12.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_LBUTTONUP:\n        nk_input_button(&d3d12.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        nk_input_button(&d3d12.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_RBUTTONDOWN:\n        nk_input_button(&d3d12.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_RBUTTONUP:\n        nk_input_button(&d3d12.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_MBUTTONDOWN:\n        nk_input_button(&d3d12.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_MBUTTONUP:\n        nk_input_button(&d3d12.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_XBUTTONDOWN:\n        switch (GET_XBUTTON_WPARAM(wparam)) {\n        case XBUTTON1:\n            nk_input_button(&d3d12.ctx, NK_BUTTON_X1, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n            break;\n        case XBUTTON2:\n            nk_input_button(&d3d12.ctx, NK_BUTTON_X2, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n            break;\n        }\n        SetCapture(wnd);\n        return 1;\n\n    case WM_XBUTTONUP:\n        switch (GET_XBUTTON_WPARAM(wparam)) {\n        case XBUTTON1:\n            nk_input_button(&d3d12.ctx, NK_BUTTON_X1, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n            break;\n        case XBUTTON2:\n            nk_input_button(&d3d12.ctx, NK_BUTTON_X2, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n            break;\n        }\n        ReleaseCapture();\n        return 1;\n\n    case WM_MOUSEWHEEL:\n        nk_input_scroll(&d3d12.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));\n        return 1;\n\n    case WM_MOUSEMOVE:\n        nk_input_motion(&d3d12.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));\n        return 1;\n\n    case WM_LBUTTONDBLCLK:\n        nk_input_button(&d3d12.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        return 1;\n    }\n\n    return 0;\n}\n\nstatic void\nnk_d3d12_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    (void)usr;\n    if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))\n    {\n        HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);\n        if (mem)\n        {\n            SIZE_T size = GlobalSize(mem) - 1;\n            if (size)\n            {\n                LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);\n                if (wstr)\n                {\n                    int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), NULL, 0, NULL, NULL);\n                    if (utf8size)\n                    {\n                        char* utf8 = (char*)malloc(utf8size);\n                        if (utf8)\n                        {\n                            WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), utf8, utf8size, NULL, NULL);\n                            nk_textedit_paste(edit, utf8, utf8size);\n                            free(utf8);\n                        }\n                    }\n                    GlobalUnlock(mem);\n                }\n            }\n        }\n        CloseClipboard();\n    }\n}\n\nstatic void\nnk_d3d12_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    (void)usr;\n    if (OpenClipboard(NULL))\n    {\n        int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);\n        if (wsize)\n        {\n            HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));\n            if (mem)\n            {\n                wchar_t* wstr = (wchar_t*)GlobalLock(mem);\n                if (wstr)\n                {\n                    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);\n                    wstr[wsize] = 0;\n                    GlobalUnlock(mem);\n                    SetClipboardData(CF_UNICODETEXT, mem);\n                }\n            }\n        }\n        CloseClipboard();\n    }\n}\n\nNK_API struct nk_context*\nnk_d3d12_init(ID3D12Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer, unsigned int max_user_textures)\n{\n    HRESULT hr;\n    D3D12_CONSTANT_BUFFER_VIEW_DESC cbv;\n    D3D12_CPU_DESCRIPTOR_HANDLE cbv_handle;\n\n    /* Do plain object / ref copys */\n    d3d12.max_vertex_buffer = max_vertex_buffer;\n    d3d12.max_index_buffer = max_index_buffer;\n    d3d12.max_user_textures = max_user_textures;\n    d3d12.device = device;\n    ID3D12Device_AddRef(device);\n    d3d12.font_texture = NULL;\n    d3d12.font_upload_buffer = NULL;\n\n    /* Init nuklear context */\n    nk_init_default(&d3d12.ctx, 0);\n    d3d12.ctx.clip.copy = nk_d3d12_clipboard_copy;\n    d3d12.ctx.clip.paste = nk_d3d12_clipboard_paste;\n    d3d12.ctx.clip.userdata = nk_handle_ptr(0);\n\n    /* Init nuklear buffer */\n    nk_buffer_init_default(&d3d12.cmds);\n\n    /* Define Heap properties */\n    d3d12.heap_prop_default.Type = D3D12_HEAP_TYPE_DEFAULT;\n    d3d12.heap_prop_default.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;\n    d3d12.heap_prop_default.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;\n    d3d12.heap_prop_default.CreationNodeMask = 0;\n    d3d12.heap_prop_default.VisibleNodeMask = 0;\n    d3d12.heap_prop_upload.Type = D3D12_HEAP_TYPE_UPLOAD;\n    d3d12.heap_prop_upload.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;\n    d3d12.heap_prop_upload.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;\n    d3d12.heap_prop_upload.CreationNodeMask = 0;\n    d3d12.heap_prop_upload.VisibleNodeMask = 0;\n\n    /* Create data objects */\n    /* Create upload buffer */\n    {\n    D3D12_RESOURCE_DESC desc;\n    desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;\n    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;\n    desc.Width = (sizeof(float) * 4 * 4) + max_vertex_buffer + max_index_buffer; /* Needs to hold matrix + vertices + indicies */\n    desc.Height = 1;\n    desc.DepthOrArraySize = 1;\n    desc.MipLevels = 1;\n    desc.Format = DXGI_FORMAT_UNKNOWN;\n    desc.SampleDesc.Count = 1;\n    desc.SampleDesc.Quality = 0;\n    desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;\n    desc.Flags = D3D12_RESOURCE_FLAG_NONE;\n    hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_upload, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource, &d3d12.upload_buffer);\n    NK_ASSERT(SUCCEEDED(hr));\n    }\n    /* Create constant buffer */\n    {\n    D3D12_RESOURCE_DESC desc;\n    desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;\n    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;\n    desc.Width = 256; /* Should be sizeof(float) * 4 * 4 - but this does not match how d3d12 works (min CBV size of 256) */\n    desc.Height = 1;\n    desc.DepthOrArraySize = 1;\n    desc.MipLevels = 1;\n    desc.Format = DXGI_FORMAT_UNKNOWN;\n    desc.SampleDesc.Count = 1;\n    desc.SampleDesc.Quality = 0;\n    desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;\n    desc.Flags = D3D12_RESOURCE_FLAG_NONE;\n    hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, &d3d12.const_buffer);\n    NK_ASSERT(SUCCEEDED(hr));\n    }\n    /* Create vertex buffer */\n    {\n    D3D12_RESOURCE_DESC desc;\n    desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;\n    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;\n    desc.Width = max_vertex_buffer;\n    desc.Height = 1;\n    desc.DepthOrArraySize = 1;\n    desc.MipLevels = 1;\n    desc.Format = DXGI_FORMAT_UNKNOWN;\n    desc.SampleDesc.Count = 1;\n    desc.SampleDesc.Quality = 0;\n    desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;\n    desc.Flags = D3D12_RESOURCE_FLAG_NONE;\n    hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, &d3d12.vertex_buffer);\n    NK_ASSERT(SUCCEEDED(hr));\n    }\n    /* Create index buffer */\n    {\n    D3D12_RESOURCE_DESC desc;\n    desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;\n    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;\n    desc.Width = max_index_buffer;\n    desc.Height = 1;\n    desc.DepthOrArraySize = 1;\n    desc.MipLevels = 1;\n    desc.Format = DXGI_FORMAT_UNKNOWN;\n    desc.SampleDesc.Count = 1;\n    desc.SampleDesc.Quality = 0;\n    desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;\n    desc.Flags = D3D12_RESOURCE_FLAG_NONE;\n    hr = ID3D12Device_CreateCommittedResource(device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COMMON, NULL, &IID_ID3D12Resource, &d3d12.index_buffer);\n    NK_ASSERT(SUCCEEDED(hr));\n    }\n\n    /* Create descriptor heap for shader root signature */\n    {\n        D3D12_DESCRIPTOR_HEAP_DESC desc;\n        desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;\n        desc.NumDescriptors = 2 + max_user_textures;\n        desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;\n        desc.NodeMask = 0;\n        ID3D12Device_CreateDescriptorHeap(device, &desc, &IID_ID3D12DescriptorHeap, &d3d12.desc_heap);\n    }\n\n    /* Get address of first handle (CPU and GPU) */\n    ID3D12DescriptorHeap_GetCPUDescriptorHandleForHeapStart(d3d12.desc_heap, &d3d12.cpu_descriptor_handle);\n    ID3D12DescriptorHeap_GetGPUDescriptorHandleForHeapStart(d3d12.desc_heap, &d3d12.gpu_descriptor_handle);\n\n    /* Get addresses of vertex & index buffers */\n    d3d12.gpu_vertex_buffer_address = ID3D12Resource_GetGPUVirtualAddress(d3d12.vertex_buffer);\n    d3d12.gpu_index_buffer_address = ID3D12Resource_GetGPUVirtualAddress(d3d12.index_buffer);\n\n    /* Get handle increment */\n    d3d12.cbv_srv_uav_desc_increment = ID3D12Device_GetDescriptorHandleIncrementSize(device, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);\n\n    /* Create view to constant buffer */\n    cbv.BufferLocation = ID3D12Resource_GetGPUVirtualAddress(d3d12.const_buffer);\n    cbv.SizeInBytes = 256;\n    cbv_handle = d3d12.cpu_descriptor_handle;\n    ID3D12Device_CreateConstantBufferView(device, &cbv, cbv_handle);\n\n    /* Create root signature */\n    hr = ID3D12Device_CreateRootSignature(device, 0, nk_d3d12_vertex_shader, sizeof(nk_d3d12_vertex_shader), &IID_ID3D12RootSignature, &d3d12.root_signature);\n    NK_ASSERT(SUCCEEDED(hr));\n\n    /* Create pipeline state */\n    {\n    /* Describe input layout */\n    const D3D12_INPUT_ELEMENT_DESC layout[] = {\n        { \"POSITION\", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, NK_OFFSETOF(struct nk_d3d12_vertex, position),  D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n        { \"TEXCOORD\", 0, DXGI_FORMAT_R32G32_FLOAT,       0, NK_OFFSETOF(struct nk_d3d12_vertex, uv),        D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n        { \"COLOR\",    0, DXGI_FORMAT_R8G8B8A8_UNORM,     0, NK_OFFSETOF(struct nk_d3d12_vertex, col),       D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },\n    };\n\n    /* Describe pipeline state */\n    D3D12_GRAPHICS_PIPELINE_STATE_DESC desc;\n    memset(&desc, 0, sizeof(desc));\n    desc.pRootSignature = d3d12.root_signature;\n    desc.VS.pShaderBytecode = nk_d3d12_vertex_shader;\n    desc.VS.BytecodeLength = sizeof(nk_d3d12_vertex_shader);\n    desc.PS.pShaderBytecode = nk_d3d12_pixel_shader;\n    desc.PS.BytecodeLength = sizeof(nk_d3d12_pixel_shader);\n    desc.BlendState.RenderTarget[0].BlendEnable = TRUE;\n    desc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;\n    desc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;\n    desc.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;\n    desc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;\n    desc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ZERO;\n    desc.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;\n    desc.BlendState.RenderTarget[0].RenderTargetWriteMask = D3D12_COLOR_WRITE_ENABLE_ALL;\n    desc.SampleMask = UINT_MAX;\n    desc.RasterizerState.FillMode = D3D12_FILL_MODE_SOLID;\n    desc.RasterizerState.CullMode= D3D12_CULL_MODE_NONE;\n    desc.RasterizerState.DepthClipEnable = TRUE;\n    desc.InputLayout.NumElements = _countof(layout);\n    desc.InputLayout.pInputElementDescs = layout;\n    desc.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE;\n    desc.NumRenderTargets = 1;\n    desc.RTVFormats[0] = DXGI_FORMAT_R8G8B8A8_UNORM; /* NOTE: When using HDR rendering you might have a different framebuffer format */\n    desc.SampleDesc.Count = 1;\n    desc.SampleDesc.Quality = 0;\n    desc.NodeMask = 0;\n\n    /* Create PSO */\n    hr = ID3D12Device_CreateGraphicsPipelineState(device, &desc, &IID_ID3D12PipelineState, &d3d12.pipeline_state);\n    NK_ASSERT(SUCCEEDED(hr));\n    }\n\n    /* First time const buffer init */\n    nk_d3d12_resize(width, height);\n\n    /* viewport */\n    d3d12.viewport.TopLeftX = 0.0f;\n    d3d12.viewport.TopLeftY = 0.0f;\n    d3d12.viewport.Width = (float)width;\n    d3d12.viewport.Height = (float)height;\n    d3d12.viewport.MinDepth = 0.0f;\n    d3d12.viewport.MaxDepth = 1.0f;\n\n    return &d3d12.ctx;\n}\n\nNK_API void\nnk_d3d12_font_stash_begin(struct nk_font_atlas **atlas)\n{\n    /* Default nuklear font stash */\n    nk_font_atlas_init_default(&d3d12.atlas);\n    nk_font_atlas_begin(&d3d12.atlas);\n    *atlas = &d3d12.atlas;\n}\n\nNK_API void\nnk_d3d12_font_stash_end(ID3D12GraphicsCommandList *command_list)\n{\n    HRESULT hr;\n    D3D12_TEXTURE_COPY_LOCATION  cpy_src, cpy_dest;\n    D3D12_BOX cpy_box;\n    D3D12_RESOURCE_BARRIER resource_barrier;\n    D3D12_SHADER_RESOURCE_VIEW_DESC srv_desc;\n    D3D12_CPU_DESCRIPTOR_HANDLE srv_handle;\n    const void *image;\n    void* ptr_data;\n    int w, h;\n\n    /* Bake nuklear font atlas */\n    image = nk_font_atlas_bake(&d3d12.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    NK_ASSERT(image);\n\n    /* Create font texture */\n    {\n    D3D12_RESOURCE_DESC desc;\n    desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D;\n    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;\n    desc.Width = w;\n    desc.Height = h;\n    desc.DepthOrArraySize = 1;\n    desc.MipLevels = 1;\n    desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n    desc.SampleDesc.Count = 1;\n    desc.SampleDesc.Quality = 0;\n    desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN;\n    desc.Flags = D3D12_RESOURCE_FLAG_NONE;\n    hr = ID3D12Device_CreateCommittedResource(d3d12.device, &d3d12.heap_prop_default, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_COPY_DEST, NULL, &IID_ID3D12Resource, &d3d12.font_texture);\n    NK_ASSERT(SUCCEEDED(hr));\n    }\n\n    /* Create font upload buffer */\n    {\n    D3D12_RESOURCE_DESC desc;\n    desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;\n    desc.Alignment = D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT;\n    desc.Width = w * h * 4;\n    desc.Height = 1;\n    desc.DepthOrArraySize = 1;\n    desc.MipLevels = 1;\n    desc.Format = DXGI_FORMAT_UNKNOWN;\n    desc.SampleDesc.Count = 1;\n    desc.SampleDesc.Quality = 0;\n    desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;\n    desc.Flags = D3D12_RESOURCE_FLAG_NONE;\n    hr = ID3D12Device_CreateCommittedResource(d3d12.device, &d3d12.heap_prop_upload, D3D12_HEAP_FLAG_NONE, &desc, D3D12_RESOURCE_STATE_GENERIC_READ, NULL, &IID_ID3D12Resource, &d3d12.font_upload_buffer);\n    NK_ASSERT(SUCCEEDED(hr));\n    }\n\n    /* Copy image data to upload buffer */\n    hr = ID3D12Resource_Map(d3d12.font_upload_buffer, 0, NULL, &ptr_data);\n    NK_ASSERT(SUCCEEDED(hr));\n    memcpy(ptr_data, image, w * h * 4);\n    ID3D12Resource_Unmap(d3d12.font_upload_buffer, 0, NULL);\n\n    /* Execute copy operation */\n    cpy_src.pResource = d3d12.font_upload_buffer;\n    cpy_src.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT;\n    cpy_src.PlacedFootprint.Offset = 0;\n    cpy_src.PlacedFootprint.Footprint.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n    cpy_src.PlacedFootprint.Footprint.Width = w;\n    cpy_src.PlacedFootprint.Footprint.Height = h;\n    cpy_src.PlacedFootprint.Footprint.Depth = 1;\n    cpy_src.PlacedFootprint.Footprint.RowPitch = w * 4;\n    cpy_dest.pResource = d3d12.font_texture;\n    cpy_dest.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX;\n    cpy_dest.SubresourceIndex = 0;\n    cpy_box.top = 0;\n    cpy_box.left = 0;\n    cpy_box.back = 1;\n    cpy_box.bottom = h;\n    cpy_box.right = w;\n    cpy_box.front = 0;\n    ID3D12GraphicsCommandList_CopyTextureRegion(command_list, &cpy_dest, 0, 0, 0, &cpy_src, &cpy_box);\n\n    /* Bring texture in the right state for rendering */\n    resource_barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION;\n    resource_barrier.Transition.pResource = d3d12.font_texture;\n    resource_barrier.Transition.Subresource = 0;\n    resource_barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_DEST;\n    resource_barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;\n    resource_barrier.Flags = D3D12_RESOURCE_BARRIER_FLAG_NONE;\n    ID3D12GraphicsCommandList_ResourceBarrier(command_list, 1, &resource_barrier);\n\n    /* Create the SRV for the font texture */\n    srv_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;\n    srv_desc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;\n    srv_desc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;\n    srv_desc.Texture2D.MipLevels = 1;\n    srv_desc.Texture2D.MostDetailedMip = 0;\n    srv_desc.Texture2D.PlaneSlice = 0;\n    srv_desc.Texture2D.ResourceMinLODClamp = 0.0f;\n    srv_handle.ptr = d3d12.cpu_descriptor_handle.ptr + d3d12.cbv_srv_uav_desc_increment;\n    ID3D12Device_CreateShaderResourceView(d3d12.device, d3d12.font_texture, &srv_desc, srv_handle);\n\n    /* Done with nk atlas data. Atlas will be served with texture id 0 */\n    nk_font_atlas_end(&d3d12.atlas, nk_handle_id(0), &d3d12.tex_null);\n\n    /* Setup default font */\n    if (d3d12.atlas.default_font)\n        nk_style_set_font(&d3d12.ctx, &d3d12.atlas.default_font->handle);\n}\n\nNK_API\nvoid nk_d3d12_font_stash_cleanup()\n{\n    if(d3d12.font_upload_buffer)\n    {\n        ID3D12Resource_Release(d3d12.font_upload_buffer);\n        d3d12.font_upload_buffer = NULL;\n    }\n}\n\nNK_API\nnk_bool nk_d3d12_set_user_texture(unsigned int index, ID3D12Resource* texture, const D3D12_SHADER_RESOURCE_VIEW_DESC* description, nk_handle* handle_out)\n{\n    nk_bool result = nk_false;\n    if(index < d3d12.max_user_textures)\n    {\n        D3D12_CPU_DESCRIPTOR_HANDLE srv_handle;\n\n        /* Get handle to texture (0 - Const Buffer; 1 - Font Texture; 2 - First user texture) */\n        srv_handle.ptr = d3d12.cpu_descriptor_handle.ptr + ((2 + index) * d3d12.cbv_srv_uav_desc_increment);\n\n        /* Create SRV */\n        ID3D12Device_CreateShaderResourceView(d3d12.device, texture, description, srv_handle);\n\n        /* Set nk handle (0 - Font Texture; 1 - First user texture) */\n        *handle_out = nk_handle_id(1 + index);\n        result = nk_true;\n    }\n\n    return result;\n}\n\nNK_API\nvoid nk_d3d12_shutdown(void)\n{\n    /* Nuklear cleanup */\n    nk_font_atlas_clear(&d3d12.atlas);\n    nk_buffer_free(&d3d12.cmds);\n    nk_free(&d3d12.ctx);\n\n    /* DirectX 12 cleanup */\n    ID3D12Device_Release(d3d12.device);\n    ID3D12PipelineState_Release(d3d12.pipeline_state);\n    ID3D12RootSignature_Release(d3d12.root_signature);\n    ID3D12DescriptorHeap_Release(d3d12.desc_heap);\n    ID3D12Resource_Release(d3d12.upload_buffer);\n    ID3D12Resource_Release(d3d12.const_buffer);\n    ID3D12Resource_Release(d3d12.index_buffer);\n    ID3D12Resource_Release(d3d12.vertex_buffer);\n    if(d3d12.font_texture)\n        ID3D12Resource_Release(d3d12.font_texture);\n    if(d3d12.font_upload_buffer)\n        ID3D12Resource_Release(d3d12.font_upload_buffer);\n}\n\n#endif\n"
  },
  {
    "path": "demo/d3d12/nuklear_d3d12.hlsl",
    "content": "#define NK_ROOTSIGNATURE \"\"\\\n\"RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT),\"\\\n\"DescriptorTable(\"\\\n  \"CBV(b0, numDescriptors = 1, flags = DATA_VOLATILE),\"\\\n  \"SRV(t0, numDescriptors = unbounded, flags = DESCRIPTORS_VOLATILE)\"\\\n\"),\"\\\n\"RootConstants(num32BitConstants = 1, b1),\"\\\n\"StaticSampler(s0, \"\\\n  \"filter = FILTER_MIN_MAG_MIP_LINEAR,\"\\\n  \"addressU = TEXTURE_ADDRESS_CLAMP,\"\\\n  \"addressV = TEXTURE_ADDRESS_CLAMP,\"\\\n  \"addressW = TEXTURE_ADDRESS_CLAMP,\"\\\n  \"comparisonFunc = COMPARISON_ALWAYS\"\\\n\")\"\n\ncbuffer buffer0 : register(b0)\n{\n  float4x4 ProjectionMatrix;\n};\ncbuffer buffer1 : register(b1)\n{\n  uint texture_index;\n};\n\nsampler sampler0 : register(s0);\nTexture2D<float4> textures[] : register(t0);\n\nstruct VS_INPUT\n{\n  float2 pos : POSITION;\n  float4 col : COLOR0;\n  float2 uv  : TEXCOORD0;\n};\n\nstruct PS_INPUT\n{\n  float4 pos : SV_POSITION;\n  float4 col : COLOR0;\n  float2 uv  : TEXCOORD0;\n};\n\n[RootSignature(NK_ROOTSIGNATURE)]\nPS_INPUT vs(VS_INPUT input)\n{\n  PS_INPUT output;\n  output.pos = mul(ProjectionMatrix, float4(input.pos.xy, 0.f, 1.f));\n  output.col = input.col;\n  output.uv  = input.uv;\n  return output;\n}\n\n[RootSignature(NK_ROOTSIGNATURE)]\nfloat4 ps(PS_INPUT input) : SV_Target\n{\n  return input.col * textures[texture_index].Sample(sampler0, input.uv);\n}\n"
  },
  {
    "path": "demo/d3d12/nuklear_d3d12_pixel_shader.h",
    "content": "#if 0\n//\n// Generated by Microsoft (R) D3D Shader Disassembler\n//\n//\n// Input signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// SV_POSITION              0   xyzw        0      POS   float       \n// COLOR                    0   xyzw        1     NONE   float   xyzw\n// TEXCOORD                 0   xy          2     NONE   float   xy  \n//\n//\n// Output signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// SV_Target                0   xyzw        0   TARGET   float   xyzw\n//\nps_5_1\ndcl_globalFlags refactoringAllowed\ndcl_constantbuffer CB0[1:1][1], immediateIndexed, space=0\ndcl_sampler S0[0:0], mode_default, space=0\ndcl_resource_texture2d (float,float,float,float) T0[0:*], space=0\ndcl_input_ps linear v1.xyzw\ndcl_input_ps linear v2.xy\ndcl_output o0.xyzw\ndcl_temps 1\nmov r0.x, CB0[1][0].x\nsample r0.xyzw, v2.xyxx, T0[r0.x + 0].xyzw, S0[0]\nmul o0.xyzw, r0.xyzw, v1.xyzw\nret \n// Approximately 0 instruction slots used\n#endif\n\nconst BYTE nk_d3d12_pixel_shader[] =\n{\n     68,  88,  66,  67,  73, 133, \n     25, 209, 159, 246,  67, 117, \n    188,  99,  71,  63,  85, 121, \n    246, 160,   1,   0,   0,   0, \n    132,   2,   0,   0,   4,   0, \n      0,   0,  48,   0,   0,   0, \n    164,   0,   0,   0, 216,   0, \n      0,   0, 212,   1,   0,   0, \n     73,  83,  71,  78, 108,   0, \n      0,   0,   3,   0,   0,   0, \n      8,   0,   0,   0,  80,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n     15,   0,   0,   0,  92,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   1,   0,   0,   0, \n     15,  15,   0,   0,  98,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   2,   0,   0,   0, \n      3,   3,   0,   0,  83,  86, \n     95,  80,  79,  83,  73,  84, \n     73,  79,  78,   0,  67,  79, \n     76,  79,  82,   0,  84,  69, \n     88,  67,  79,  79,  82,  68, \n      0, 171,  79,  83,  71,  78, \n     44,   0,   0,   0,   1,   0, \n      0,   0,   8,   0,   0,   0, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   0,   0, \n      0,   0,  15,   0,   0,   0, \n     83,  86,  95,  84,  97, 114, \n    103, 101, 116,   0, 171, 171, \n     83,  72,  69,  88, 244,   0, \n      0,   0,  81,   0,   0,   0, \n     61,   0,   0,   0, 106,   8, \n      0,   1,  89,   0,   0,   7, \n     70, 142,  48,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      1,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n     90,   0,   0,   6,  70, 110, \n     48,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n     88,  24,   0,   7,  70, 126, \n     48,   0,   0,   0,   0,   0, \n      0,   0,   0,   0, 255, 255, \n    255, 255,  85,  85,   0,   0, \n      0,   0,   0,   0,  98,  16, \n      0,   3, 242,  16,  16,   0, \n      1,   0,   0,   0,  98,  16, \n      0,   3,  50,  16,  16,   0, \n      2,   0,   0,   0, 101,   0, \n      0,   3, 242,  32,  16,   0, \n      0,   0,   0,   0, 104,   0, \n      0,   2,   1,   0,   0,   0, \n     54,   0,   0,   7,  18,   0, \n     16,   0,   0,   0,   0,   0, \n     10, 128,  48,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,  69,   0, \n      0,  12, 242,   0,  16,   0, \n      0,   0,   0,   0,  70,  16, \n     16,   0,   2,   0,   0,   0, \n     70, 126,  32,   4,   0,   0, \n      0,   0,  10,   0,  16,   0, \n      0,   0,   0,   0,   0,  96, \n     32,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  56,   0, \n      0,   7, 242,  32,  16,   0, \n      0,   0,   0,   0,  70,  14, \n     16,   0,   0,   0,   0,   0, \n     70,  30,  16,   0,   1,   0, \n      0,   0,  62,   0,   0,   1, \n     82,  84,  83,  48, 168,   0, \n      0,   0,   2,   0,   0,   0, \n      2,   0,   0,   0,  24,   0, \n      0,   0,   1,   0,   0,   0, \n    116,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,  48,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0, 104,   0, \n      0,   0,   2,   0,   0,   0, \n     56,   0,   0,   0,   2,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   2,   0,   0,   0, \n    255, 255, 255, 255,   0,   0, \n      0,   0, 255, 255, 255, 255, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n    255, 255, 255, 255,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      3,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n     16,   0,   0,   0,   8,   0, \n      0,   0,   2,   0,   0,   0, \n      0,   0,   0,   0, 255, 255, \n    127, 127,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0\n};\n"
  },
  {
    "path": "demo/d3d12/nuklear_d3d12_vertex_shader.h",
    "content": "#if 0\n//\n// Generated by Microsoft (R) D3D Shader Disassembler\n//\n//\n// Input signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// POSITION                 0   xy          0     NONE   float   xy  \n// COLOR                    0   xyzw        1     NONE   float   xyzw\n// TEXCOORD                 0   xy          2     NONE   float   xy  \n//\n//\n// Output signature:\n//\n// Name                 Index   Mask Register SysValue  Format   Used\n// -------------------- ----- ------ -------- -------- ------- ------\n// SV_POSITION              0   xyzw        0      POS   float   xyzw\n// COLOR                    0   xyzw        1     NONE   float   xyzw\n// TEXCOORD                 0   xy          2     NONE   float   xy  \n//\nvs_5_1\ndcl_globalFlags refactoringAllowed\ndcl_constantbuffer CB0[0:0][4], immediateIndexed, space=0\ndcl_input v0.xy\ndcl_input v1.xyzw\ndcl_input v2.xy\ndcl_output_siv o0.xyzw, position\ndcl_output o1.xyzw\ndcl_output o2.xy\ndcl_temps 1\nmul r0.xyzw, v0.yyyy, CB0[0][1].xyzw\nmad r0.xyzw, CB0[0][0].xyzw, v0.xxxx, r0.xyzw\nadd o0.xyzw, r0.xyzw, CB0[0][3].xyzw\nmov o1.xyzw, v1.xyzw\nmov o2.xy, v2.xyxx\nret \n// Approximately 0 instruction slots used\n#endif\n\nconst BYTE nk_d3d12_vertex_shader[] =\n{\n     68,  88,  66,  67,  10,  50, \n    163, 106,  14, 182,  90, 117, \n    132,  23,  91, 245,  57, 254, \n    217,  51,   1,   0,   0,   0, \n    232,   2,   0,   0,   4,   0, \n      0,   0,  48,   0,   0,   0, \n    160,   0,   0,   0,  20,   1, \n      0,   0,  56,   2,   0,   0, \n     73,  83,  71,  78, 104,   0, \n      0,   0,   3,   0,   0,   0, \n      8,   0,   0,   0,  80,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   3,   0,   0,  89,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   1,   0,   0,   0, \n     15,  15,   0,   0,  95,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,   2,   0,   0,   0, \n      3,   3,   0,   0,  80,  79, \n     83,  73,  84,  73,  79,  78, \n      0,  67,  79,  76,  79,  82, \n      0,  84,  69,  88,  67,  79, \n     79,  82,  68,   0,  79,  83, \n     71,  78, 108,   0,   0,   0, \n      3,   0,   0,   0,   8,   0, \n      0,   0,  80,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,  15,   0, \n      0,   0,  92,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      1,   0,   0,   0,  15,   0, \n      0,   0,  98,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   3,   0,   0,   0, \n      2,   0,   0,   0,   3,  12, \n      0,   0,  83,  86,  95,  80, \n     79,  83,  73,  84,  73,  79, \n     78,   0,  67,  79,  76,  79, \n     82,   0,  84,  69,  88,  67, \n     79,  79,  82,  68,   0, 171, \n     83,  72,  69,  88,  28,   1, \n      0,   0,  81,   0,   1,   0, \n     71,   0,   0,   0, 106,   8, \n      0,   1,  89,   0,   0,   7, \n     70, 142,  48,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   4,   0, \n      0,   0,   0,   0,   0,   0, \n     95,   0,   0,   3,  50,  16, \n     16,   0,   0,   0,   0,   0, \n     95,   0,   0,   3, 242,  16, \n     16,   0,   1,   0,   0,   0, \n     95,   0,   0,   3,  50,  16, \n     16,   0,   2,   0,   0,   0, \n    103,   0,   0,   4, 242,  32, \n     16,   0,   0,   0,   0,   0, \n      1,   0,   0,   0, 101,   0, \n      0,   3, 242,  32,  16,   0, \n      1,   0,   0,   0, 101,   0, \n      0,   3,  50,  32,  16,   0, \n      2,   0,   0,   0, 104,   0, \n      0,   2,   1,   0,   0,   0, \n     56,   0,   0,   9, 242,   0, \n     16,   0,   0,   0,   0,   0, \n     86,  21,  16,   0,   0,   0, \n      0,   0,  70, 142,  48,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   1,   0,   0,   0, \n     50,   0,   0,  11, 242,   0, \n     16,   0,   0,   0,   0,   0, \n     70, 142,  48,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   6,  16, \n     16,   0,   0,   0,   0,   0, \n     70,  14,  16,   0,   0,   0, \n      0,   0,   0,   0,   0,   9, \n    242,  32,  16,   0,   0,   0, \n      0,   0,  70,  14,  16,   0, \n      0,   0,   0,   0,  70, 142, \n     48,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   3,   0, \n      0,   0,  54,   0,   0,   5, \n    242,  32,  16,   0,   1,   0, \n      0,   0,  70,  30,  16,   0, \n      1,   0,   0,   0,  54,   0, \n      0,   5,  50,  32,  16,   0, \n      2,   0,   0,   0,  70,  16, \n     16,   0,   2,   0,   0,   0, \n     62,   0,   0,   1,  82,  84, \n     83,  48, 168,   0,   0,   0, \n      2,   0,   0,   0,   2,   0, \n      0,   0,  24,   0,   0,   0, \n      1,   0,   0,   0, 116,   0, \n      0,   0,   1,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      0,   0,  48,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0, 104,   0,   0,   0, \n      2,   0,   0,   0,  56,   0, \n      0,   0,   2,   0,   0,   0, \n      1,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      2,   0,   0,   0, 255, 255, \n    255, 255,   0,   0,   0,   0, \n    255, 255, 255, 255,   0,   0, \n      0,   0,   0,   0,   0,   0, \n      1,   0,   0,   0, 255, 255, \n    255, 255,   1,   0,   0,   0, \n      0,   0,   0,   0,   1,   0, \n      0,   0,   0,   0,   0,   0, \n      3,   0,   0,   0,   3,   0, \n      0,   0,   3,   0,   0,   0, \n      0,   0,   0,   0,  16,   0, \n      0,   0,   8,   0,   0,   0, \n      2,   0,   0,   0,   0,   0, \n      0,   0, 255, 255, 127, 127, \n      0,   0,   0,   0,   0,   0, \n      0,   0,   0,   0,   0,   0\n};\n"
  },
  {
    "path": "demo/d3d9/build.bat",
    "content": "@echo off\n\nrem This will use VS2015 for compiler\ncall \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat\" x86\n\ncl /D_CRT_SECURE_NO_DEPRECATE /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib d3d9.lib /link /incremental:no\n"
  },
  {
    "path": "demo/d3d9/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n#define COBJMACROS\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <d3d9.h>\n#include <stdio.h>\n#include <string.h>\n#include <limits.h>\n#include <time.h>\n\n#define WINDOW_WIDTH 800\n#define WINDOW_HEIGHT 600\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_D3D9_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_d3d9.h\"\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nstatic IDirect3DDevice9 *device;\nstatic IDirect3DDevice9Ex *deviceEx;\nstatic D3DPRESENT_PARAMETERS present;\n\nstatic LRESULT CALLBACK\nWindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)\n{\n    switch (msg)\n    {\n    case WM_DESTROY:\n        PostQuitMessage(0);\n        return 0;\n\n    case WM_SIZE:\n        if (device)\n        {\n            UINT width = LOWORD(lparam);\n            UINT height = HIWORD(lparam);\n            if (width != 0 && height != 0 &&\n                (width != present.BackBufferWidth || height != present.BackBufferHeight))\n            {\n                HRESULT hr;\n                nk_d3d9_release();\n                present.BackBufferWidth = width;\n                present.BackBufferHeight = height;\n                hr = IDirect3DDevice9_Reset(device, &present);\n                NK_ASSERT(SUCCEEDED(hr));\n                nk_d3d9_resize(width, height);\n            }\n        }\n        break;\n    }\n\n    if (nk_d3d9_handle_event(wnd, msg, wparam, lparam))\n        return 0;\n\n    return DefWindowProcW(wnd, msg, wparam, lparam);\n}\n\nstatic void create_d3d9_device(HWND wnd)\n{\n    HRESULT hr;\n\n    present.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;\n    present.BackBufferWidth = WINDOW_WIDTH;\n    present.BackBufferHeight = WINDOW_HEIGHT;\n    present.BackBufferFormat = D3DFMT_X8R8G8B8;\n    present.BackBufferCount = 1;\n    present.MultiSampleType = D3DMULTISAMPLE_NONE;\n    present.SwapEffect = D3DSWAPEFFECT_DISCARD;\n    present.hDeviceWindow = wnd;\n    present.EnableAutoDepthStencil = TRUE;\n    present.AutoDepthStencilFormat = D3DFMT_D24S8;\n    present.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;\n    present.Windowed = TRUE;\n\n    {/* first try to create Direct3D9Ex device if possible (on Windows 7+) */\n        typedef HRESULT WINAPI Direct3DCreate9ExPtr(UINT, IDirect3D9Ex**);\n        Direct3DCreate9ExPtr *Direct3DCreate9Ex = (void *)GetProcAddress(GetModuleHandleA(\"d3d9.dll\"), \"Direct3DCreate9Ex\");\n        if (Direct3DCreate9Ex) {\n            IDirect3D9Ex *d3d9ex;\n            if (SUCCEEDED(Direct3DCreate9Ex(D3D_SDK_VERSION, &d3d9ex))) {\n                hr = IDirect3D9Ex_CreateDeviceEx(d3d9ex, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,\n                    D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,\n                    &present, NULL, &deviceEx);\n                if (SUCCEEDED(hr)) {\n                    device = (IDirect3DDevice9 *)deviceEx;\n                } else {\n                    /* hardware vertex processing not supported, no big deal\n                    retry with software vertex processing */\n                    hr = IDirect3D9Ex_CreateDeviceEx(d3d9ex, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,\n                        D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,\n                        &present, NULL, &deviceEx);\n                    if (SUCCEEDED(hr)) {\n                        device = (IDirect3DDevice9 *)deviceEx;\n                    }\n                }\n                IDirect3D9Ex_Release(d3d9ex);\n            }\n        }\n    }\n\n    if (!device) {\n        /* otherwise do regular D3D9 setup */\n        IDirect3D9 *d3d9 = Direct3DCreate9(D3D_SDK_VERSION);\n\n        hr = IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,\n            D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,\n            &present, &device);\n        if (FAILED(hr)) {\n            /* hardware vertex processing not supported, no big deal\n            retry with software vertex processing */\n            hr = IDirect3D9_CreateDevice(d3d9, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, wnd,\n                D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE | D3DCREATE_FPU_PRESERVE,\n                &present, &device);\n            NK_ASSERT(SUCCEEDED(hr));\n        }\n        IDirect3D9_Release(d3d9);\n    }\n}\n\nint main(void)\n{\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n\n    WNDCLASSW wc;\n    RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };\n    DWORD style = WS_OVERLAPPEDWINDOW;\n    DWORD exstyle = WS_EX_APPWINDOW;\n    HWND wnd;\n    int running = 1;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    /* Win32 */\n    memset(&wc, 0, sizeof(wc));\n    wc.style = CS_DBLCLKS;\n    wc.lpfnWndProc = WindowProc;\n    wc.hInstance = GetModuleHandleW(0);\n    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);\n    wc.hCursor = LoadCursor(NULL, IDC_ARROW);\n    wc.lpszClassName = L\"NuklearWindowClass\";\n    RegisterClassW(&wc);\n\n    AdjustWindowRectEx(&rect, style, FALSE, exstyle);\n\n    wnd = CreateWindowExW(exstyle, wc.lpszClassName, L\"Nuklear Direct3D 9 Demo\",\n        style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,\n        rect.right - rect.left, rect.bottom - rect.top,\n        NULL, NULL, wc.hInstance, NULL);\n\n    create_d3d9_device(wnd);\n\n    /* GUI */\n    ctx = nk_d3d9_init(device, WINDOW_WIDTH, WINDOW_HEIGHT);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {struct nk_font_atlas *atlas;\n    nk_d3d9_font_stash_begin(&atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *robot = nk_font_atlas_add_from_file(atlas, \"../../extra_font/Roboto-Regular.ttf\", 14, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_d3d9_font_stash_end();\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &droid->handle)*/;}\n\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (running)\n    {\n        /* Input */\n        MSG msg;\n        nk_input_begin(ctx);\n        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {\n            if (msg.message == WM_QUIT)\n                running = 0;\n            TranslateMessage(&msg);\n            DispatchMessageW(&msg);\n        }\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 22, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        {\n            HRESULT hr;\n            hr = IDirect3DDevice9_Clear(device, 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,\n                D3DCOLOR_COLORVALUE(bg.r, bg.g, bg.b, bg.a), 0.0f, 0);\n            NK_ASSERT(SUCCEEDED(hr));\n\n            hr = IDirect3DDevice9_BeginScene(device);\n            NK_ASSERT(SUCCEEDED(hr));\n            nk_d3d9_render(NK_ANTI_ALIASING_ON);\n            hr = IDirect3DDevice9_EndScene(device);\n            NK_ASSERT(SUCCEEDED(hr));\n\n            if (deviceEx) {\n                hr = IDirect3DDevice9Ex_PresentEx(deviceEx, NULL, NULL, NULL, NULL, 0);\n            } else {\n                hr = IDirect3DDevice9_Present(device, NULL, NULL, NULL, NULL);\n            }\n            if (hr == D3DERR_DEVICELOST || hr == D3DERR_DEVICEHUNG || hr == D3DERR_DEVICEREMOVED) {\n                /* to recover from this, you'll need to recreate device and all the resources */\n                MessageBoxW(NULL, L\"D3D9 device is lost or removed!\", L\"Error\", 0);\n                break;\n            } else if (hr == S_PRESENT_OCCLUDED) {\n                /* window is not visible, so vsync won't work. Let's sleep a bit to reduce CPU usage */\n                Sleep(10);\n            }\n            NK_ASSERT(SUCCEEDED(hr));\n        }\n    }\n    nk_d3d9_shutdown();\n    if (deviceEx)IDirect3DDevice9Ex_Release(deviceEx);\n    else IDirect3DDevice9_Release(device);\n    UnregisterClassW(wc.lpszClassName, wc.hInstance);\n    return 0;\n}\n"
  },
  {
    "path": "demo/d3d9/nuklear_d3d9.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_D3D9_H_\n#define NK_D3D9_H_\n\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n\ntypedef struct IDirect3DDevice9 IDirect3DDevice9;\n\nNK_API struct nk_context *nk_d3d9_init(IDirect3DDevice9 *device, int width, int height);\nNK_API void nk_d3d9_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void nk_d3d9_font_stash_end(void);\nNK_API int nk_d3d9_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);\nNK_API void nk_d3d9_render(enum nk_anti_aliasing);\nNK_API void nk_d3d9_release(void);\nNK_API void nk_d3d9_resize(int width, int height);\nNK_API void nk_d3d9_shutdown(void);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_D3D9_IMPLEMENTATION\n\n#define WIN32_LEAN_AND_MEAN\n#define COBJMACROS\n#include <d3d9.h>\n\n#include <stdlib.h>\n#include <stddef.h>\n#include <string.h>\n\nstruct nk_d3d9_vertex {\n    /* D3d9 FFP requires three coordinate position, but nuklear writes only 2 elements\n       projection matrix doesn't use z coordinate => so it can be any value.\n       Member order here is important! Do not rearrange them! */\n    float position[3];\n    nk_uchar col[4];\n    float uv[2];\n};\n\nstatic struct {\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    struct nk_buffer cmds;\n\n    struct nk_draw_null_texture tex_null;\n\n    D3DVIEWPORT9 viewport;\n    D3DMATRIX projection;\n    IDirect3DDevice9 *device;\n    IDirect3DTexture9 *texture;\n    IDirect3DStateBlock9 *state;\n} d3d9;\n\nNK_API void\nnk_d3d9_create_state()\n{\n    HRESULT hr;\n\n    hr = IDirect3DDevice9_BeginStateBlock(d3d9.device);\n    NK_ASSERT(SUCCEEDED(hr));\n\n    /* vertex format */\n    IDirect3DDevice9_SetFVF(d3d9.device, D3DFVF_XYZ + D3DFVF_DIFFUSE + D3DFVF_TEX1);\n\n    /* blend state */\n    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);\n    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);\n    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ALPHABLENDENABLE, TRUE);\n    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_BLENDOP, D3DBLENDOP_ADD);\n\n    /* render state */\n    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_LIGHTING, FALSE);\n    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ZENABLE, FALSE);\n    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_ZWRITEENABLE, FALSE);\n    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_CULLMODE, D3DCULL_NONE);\n    IDirect3DDevice9_SetRenderState(d3d9.device, D3DRS_SCISSORTESTENABLE, TRUE);\n\n    /* sampler state */\n    IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);\n    IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);\n    IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);\n    IDirect3DDevice9_SetSamplerState(d3d9.device, 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);\n\n    /* texture stage state */\n    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLOROP, D3DTOP_MODULATE);\n    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE);\n    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);\n    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);\n    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);\n    IDirect3DDevice9_SetTextureStageState(d3d9.device, 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);\n\n    hr = IDirect3DDevice9_EndStateBlock(d3d9.device, &d3d9.state);\n    NK_ASSERT(SUCCEEDED(hr));\n}\n\nNK_API void\nnk_d3d9_render(enum nk_anti_aliasing AA)\n{\n    HRESULT hr;\n\n    nk_d3d9_create_state();\n\n    hr = IDirect3DStateBlock9_Apply(d3d9.state);\n    NK_ASSERT(SUCCEEDED(hr));\n\n    /* projection matrix */\n    IDirect3DDevice9_SetTransform(d3d9.device, D3DTS_PROJECTION, &d3d9.projection);\n\n    /* viewport */\n    IDirect3DDevice9_SetViewport(d3d9.device, &d3d9.viewport);\n\n    /* convert from command queue into draw list and draw to screen */\n    {\n        struct nk_buffer vbuf, ebuf;\n        const struct nk_draw_command *cmd;\n        const nk_draw_index *offset = NULL;\n        UINT vertex_count;\n\n        /* fill converting configuration */\n        struct nk_convert_config config;\n        NK_STORAGE const struct nk_draw_vertex_layout_element vertex_layout[] = {\n            {NK_VERTEX_POSITION, NK_FORMAT_FLOAT,    NK_OFFSETOF(struct nk_d3d9_vertex, position)},\n            {NK_VERTEX_COLOR,    NK_FORMAT_B8G8R8A8, NK_OFFSETOF(struct nk_d3d9_vertex, col)},\n            {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT,    NK_OFFSETOF(struct nk_d3d9_vertex, uv)},\n            {NK_VERTEX_LAYOUT_END}\n        };\n        memset(&config, 0, sizeof(config));\n        config.vertex_layout = vertex_layout;\n        config.vertex_size = sizeof(struct nk_d3d9_vertex);\n        config.vertex_alignment = NK_ALIGNOF(struct nk_d3d9_vertex);\n        config.global_alpha = 1.0f;\n        config.shape_AA = AA;\n        config.line_AA = AA;\n        config.circle_segment_count = 22;\n        config.curve_segment_count = 22;\n        config.arc_segment_count = 22;\n        config.tex_null = d3d9.tex_null;\n\n        /* convert shapes into vertexes */\n        nk_buffer_init_default(&vbuf);\n        nk_buffer_init_default(&ebuf);\n        nk_convert(&d3d9.ctx, &d3d9.cmds, &vbuf, &ebuf, &config);\n\n        /* iterate over and execute each draw command */\n        offset = (const nk_draw_index *)nk_buffer_memory_const(&ebuf);\n        vertex_count = (UINT)vbuf.needed / sizeof(struct nk_d3d9_vertex);\n\n        nk_draw_foreach(cmd, &d3d9.ctx, &d3d9.cmds)\n        {\n            RECT scissor;\n            if (!cmd->elem_count) continue;\n\n            hr = IDirect3DDevice9_SetTexture(d3d9.device, 0, (IDirect3DBaseTexture9 *)cmd->texture.ptr);\n            NK_ASSERT(SUCCEEDED(hr));\n\n            scissor.left = (LONG)cmd->clip_rect.x;\n            scissor.right = (LONG)(cmd->clip_rect.x + cmd->clip_rect.w);\n            scissor.top = (LONG)cmd->clip_rect.y;\n            scissor.bottom = (LONG)(cmd->clip_rect.y + cmd->clip_rect.h);\n\n            hr = IDirect3DDevice9_SetScissorRect(d3d9.device, &scissor);\n            NK_ASSERT(SUCCEEDED(hr));\n\n            NK_ASSERT(sizeof(nk_draw_index) == sizeof(NK_UINT16));\n            hr = IDirect3DDevice9_DrawIndexedPrimitiveUP(d3d9.device, D3DPT_TRIANGLELIST,\n                0, vertex_count, cmd->elem_count/3, offset, D3DFMT_INDEX16,\n                nk_buffer_memory_const(&vbuf), sizeof(struct nk_d3d9_vertex));\n            NK_ASSERT(SUCCEEDED(hr));\n            offset += cmd->elem_count;\n        }\n\n        nk_buffer_free(&vbuf);\n        nk_buffer_free(&ebuf);\n    }\n\n    nk_clear(&d3d9.ctx);\n    nk_buffer_clear(&d3d9.cmds);\n\n    IDirect3DStateBlock9_Apply(d3d9.state);\n    IDirect3DStateBlock9_Release(d3d9.state);\n}\n\nstatic void\nnk_d3d9_get_projection_matrix(int width, int height, float *result)\n{\n    const float L = 0.5f;\n    const float R = (float)width + 0.5f;\n    const float T = 0.5f;\n    const float B = (float)height + 0.5f;\n    float matrix[4][4] = {\n        { 0.0f, 0.0f, 0.0f, 0.0f },\n        { 0.0f, 0.0f, 0.0f, 0.0f },\n        { 0.0f, 0.0f, 0.0f, 0.0f },\n        { 0.0f, 0.0f, 0.0f, 1.0f },\n    };\n    matrix[0][0] = 2.0f / (R - L);\n    matrix[1][1] = 2.0f / (T - B);\n    matrix[3][0] = (R + L) / (L - R);\n    matrix[3][1] = (T + B) / (B - T);\n    memcpy(result, matrix, sizeof(matrix));\n}\n\nNK_API void\nnk_d3d9_release(void)\n{\n    IDirect3DTexture9_Release(d3d9.texture);\n}\n\nstatic void\nnk_d3d9_create_font_texture()\n{\n    int w, h, y;\n    const void *image;\n\n    HRESULT hr;\n    D3DLOCKED_RECT locked;\n\n    image = nk_font_atlas_bake(&d3d9.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n\n    hr = IDirect3DDevice9_CreateTexture(d3d9.device, w, h, 1, D3DUSAGE_DYNAMIC, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &d3d9.texture, NULL);\n    NK_ASSERT(SUCCEEDED(hr));\n\n    hr = IDirect3DTexture9_LockRect(d3d9.texture, 0, &locked, NULL, 0);\n    NK_ASSERT(SUCCEEDED(hr));\n\n    for (y = 0; y < h; y++) {\n        void *src = (char *)image + y * w * 4;\n        void *dst = (char *)locked.pBits + y * locked.Pitch;\n        memcpy(dst, src, w * 4);\n    }\n\n    hr = IDirect3DTexture9_UnlockRect(d3d9.texture, 0);\n    NK_ASSERT(SUCCEEDED(hr));\n\n    nk_font_atlas_end(&d3d9.atlas, nk_handle_ptr(d3d9.texture), &d3d9.tex_null);\n}\n\nNK_API void\nnk_d3d9_resize(int width, int height)\n{\n    if (d3d9.texture) {\n        nk_d3d9_create_font_texture();\n    }\n\n    nk_d3d9_create_state();\n\n    nk_d3d9_get_projection_matrix(width, height, &d3d9.projection.m[0][0]);\n    d3d9.viewport.Width = width;\n    d3d9.viewport.Height = height;\n}\n\nNK_API int\nnk_d3d9_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)\n{\n    static int insert_toggle = 0;\n    switch (msg)\n    {\n    case WM_KEYDOWN:\n    case WM_KEYUP:\n    case WM_SYSKEYDOWN:\n    case WM_SYSKEYUP:\n    {\n        int down = !((lparam >> 31) & 1);\n        int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);\n\n        switch (wparam)\n        {\n        case VK_SHIFT:\n        case VK_LSHIFT:\n        case VK_RSHIFT:\n            nk_input_key(&d3d9.ctx, NK_KEY_SHIFT, down);\n            return 1;\n\n        case VK_DELETE:\n            nk_input_key(&d3d9.ctx, NK_KEY_DEL, down);\n            return 1;\n\n        case VK_RETURN:\n        case VK_SEPARATOR:\n            nk_input_key(&d3d9.ctx, NK_KEY_ENTER, down);\n            return 1;\n\n        case VK_TAB:\n            nk_input_key(&d3d9.ctx, NK_KEY_TAB, down);\n            return 1;\n\n        case VK_LEFT:\n            if (ctrl)\n                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else\n                nk_input_key(&d3d9.ctx, NK_KEY_LEFT, down);\n            return 1;\n\n        case VK_RIGHT:\n            if (ctrl)\n                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else\n                nk_input_key(&d3d9.ctx, NK_KEY_RIGHT, down);\n            return 1;\n\n        case VK_BACK:\n            nk_input_key(&d3d9.ctx, NK_KEY_BACKSPACE, down);\n            return 1;\n\n        case VK_HOME:\n            nk_input_key(&d3d9.ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_START, down);\n            return 1;\n\n        case VK_END:\n            nk_input_key(&d3d9.ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_END, down);\n            return 1;\n\n        case VK_NEXT:\n            nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_DOWN, down);\n            return 1;\n\n        case VK_PRIOR:\n            nk_input_key(&d3d9.ctx, NK_KEY_SCROLL_UP, down);\n            return 1;\n\n        case VK_ESCAPE:\n            nk_input_key(&d3d9.ctx, NK_KEY_TEXT_RESET_MODE, down);\n            return 1;\n\n        case VK_INSERT:\n        /* Only switch on release to avoid repeat issues\n         * kind of confusing since we have to negate it but we're already\n         * hacking it since Nuklear treats them as two separate keys rather\n         * than a single toggle state */\n            if (!down) {\n                insert_toggle = !insert_toggle;\n                if (insert_toggle) {\n                    nk_input_key(&d3d9.ctx, NK_KEY_TEXT_INSERT_MODE, !down);\n                    /* nk_input_key(&d3d9.ctx, NK_KEY_TEXT_REPLACE_MODE, down); */\n                } else {\n                    nk_input_key(&d3d9.ctx, NK_KEY_TEXT_REPLACE_MODE, !down);\n                    /* nk_input_key(&d3d9.ctx, NK_KEY_TEXT_INSERT_MODE, down); */\n                }\n            }\n            return 1;\n\n        case 'A':\n            if (ctrl) {\n                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_SELECT_ALL, down);\n                return 1;\n            }\n            break;\n\n        case 'B':\n            if (ctrl) {\n                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_LINE_START, down);\n                return 1;\n            }\n            break;\n\n        case 'E':\n            if (ctrl) {\n                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_LINE_END, down);\n                return 1;\n            }\n            break;\n\n        case 'C':\n            if (ctrl) {\n                nk_input_key(&d3d9.ctx, NK_KEY_COPY, down);\n                return 1;\n            }\n            break;\n\n        case 'V':\n            if (ctrl) {\n                nk_input_key(&d3d9.ctx, NK_KEY_PASTE, down);\n                return 1;\n            }\n            break;\n\n        case 'X':\n            if (ctrl) {\n                nk_input_key(&d3d9.ctx, NK_KEY_CUT, down);\n                return 1;\n            }\n            break;\n\n        case 'Z':\n            if (ctrl) {\n                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_UNDO, down);\n                return 1;\n            }\n            break;\n\n        case 'R':\n            if (ctrl) {\n                nk_input_key(&d3d9.ctx, NK_KEY_TEXT_REDO, down);\n                return 1;\n            }\n            break;\n        }\n        return 0;\n    }\n\n    case WM_CHAR:\n        if (wparam >= 32)\n        {\n            nk_input_unicode(&d3d9.ctx, (nk_rune)wparam);\n            return 1;\n        }\n        break;\n\n    case WM_LBUTTONDOWN:\n        nk_input_button(&d3d9.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_LBUTTONUP:\n        nk_input_button(&d3d9.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        nk_input_button(&d3d9.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_RBUTTONDOWN:\n        nk_input_button(&d3d9.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_RBUTTONUP:\n        nk_input_button(&d3d9.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_MBUTTONDOWN:\n        nk_input_button(&d3d9.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_MBUTTONUP:\n        nk_input_button(&d3d9.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_XBUTTONDOWN:\n        switch (GET_XBUTTON_WPARAM(wparam)) {\n        case XBUTTON1:\n            nk_input_button(&d3d9.ctx, NK_BUTTON_X1, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n            break;\n        case XBUTTON2:\n            nk_input_button(&d3d9.ctx, NK_BUTTON_X2, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n            break;\n        }\n        SetCapture(wnd);\n        return 1;\n\n    case WM_XBUTTONUP:\n        switch (GET_XBUTTON_WPARAM(wparam)) {\n        case XBUTTON1:\n            nk_input_button(&d3d9.ctx, NK_BUTTON_X1, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n            break;\n        case XBUTTON2:\n            nk_input_button(&d3d9.ctx, NK_BUTTON_X2, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n            break;\n        }\n        ReleaseCapture();\n        return 1;\n\n    case WM_MOUSEWHEEL:\n        nk_input_scroll(&d3d9.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));\n        return 1;\n\n    case WM_MOUSEMOVE:\n        nk_input_motion(&d3d9.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));\n        return 1;\n\n    case WM_LBUTTONDBLCLK:\n        nk_input_button(&d3d9.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        return 1;\n    }\n\n    return 0;\n}\n\nstatic void\nnk_d3d9_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    HGLOBAL mem;\n    SIZE_T size;\n    LPCWSTR wstr;\n    int utf8size;\n\n    (void)usr;\n    if (!IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) {\n        return;\n    }\n\n    mem = GetClipboardData(CF_UNICODETEXT);\n    if (!mem) {\n        CloseClipboard();\n        return;\n    }\n\n    size = GlobalSize(mem) - 1;\n    if (!size) {\n        CloseClipboard();\n        return;\n    }\n\n    wstr = (LPCWSTR)GlobalLock(mem);\n    if (!wstr) {\n        CloseClipboard();\n        return;\n    }\n\n    utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)size / sizeof(wchar_t), NULL, 0, NULL, NULL);\n    if (utf8size) {\n        char *utf8 = (char *)malloc(utf8size);\n        if (utf8) {\n            WideCharToMultiByte(CP_UTF8, 0, wstr, (int)size / sizeof(wchar_t), utf8, utf8size, NULL, NULL);\n            nk_textedit_paste(edit, utf8, utf8size);\n            free(utf8);\n        }\n    }\n\n    GlobalUnlock(mem);\n    CloseClipboard();\n}\n\nstatic void\nnk_d3d9_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    int wsize;\n\n    (void)usr;\n    if (!OpenClipboard(NULL)) {\n        return;\n    }\n\n    wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);\n    if (wsize) {\n        HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));\n        if (mem) {\n            wchar_t *wstr = (wchar_t*)GlobalLock(mem);\n            if (wstr) {\n                MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);\n                wstr[wsize] = 0;\n                GlobalUnlock(mem);\n                SetClipboardData(CF_UNICODETEXT, mem);\n            }\n        }\n    }\n\n    CloseClipboard();\n}\n\nNK_API struct nk_context*\nnk_d3d9_init(IDirect3DDevice9 *device, int width, int height)\n{\n    d3d9.device = device;\n    IDirect3DDevice9_AddRef(device);\n\n    nk_init_default(&d3d9.ctx, 0);\n    d3d9.state = NULL;\n    d3d9.texture = NULL;\n    d3d9.ctx.clip.copy = nk_d3d9_clipboard_copy;\n    d3d9.ctx.clip.paste = nk_d3d9_clipboard_paste;\n    d3d9.ctx.clip.userdata = nk_handle_ptr(0);\n\n    nk_buffer_init_default(&d3d9.cmds);\n\n    /* viewport */\n    d3d9.viewport.X = 0;\n    d3d9.viewport.Y = 0;\n    d3d9.viewport.MinZ = 0.0f;\n    d3d9.viewport.MaxZ = 1.0f;\n\n    nk_d3d9_resize(width, height);\n\n    return &d3d9.ctx;\n}\n\nNK_API void\nnk_d3d9_font_stash_begin(struct nk_font_atlas **atlas)\n{\n    nk_font_atlas_init_default(&d3d9.atlas);\n    nk_font_atlas_begin(&d3d9.atlas);\n    *atlas = &d3d9.atlas;\n}\n\nNK_API void\nnk_d3d9_font_stash_end(void)\n{\n    nk_d3d9_create_font_texture();\n\n    if (d3d9.atlas.default_font)\n        nk_style_set_font(&d3d9.ctx, &d3d9.atlas.default_font->handle);\n}\n\nNK_API\nvoid nk_d3d9_shutdown(void)\n{\n    nk_d3d9_release();\n\n    nk_font_atlas_clear(&d3d9.atlas);\n    nk_buffer_free(&d3d9.cmds);\n    nk_free(&d3d9.ctx);\n}\n\n#endif\n"
  },
  {
    "path": "demo/gdi/build.bat",
    "content": "@echo off\n\nrem This will use VS2015 for compiler\ncall \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat\" x86\n\ncl /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe main.c user32.lib gdi32.lib Msimg32.lib /link /incremental:no\n"
  },
  {
    "path": "demo/gdi/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <stdio.h>\n#include <string.h>\n#include <time.h>\n#include <limits.h>\n\n#define WINDOW_WIDTH 800\n#define WINDOW_HEIGHT 600\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_IMPLEMENTATION\n#define NK_GDI_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_gdi.h\"\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nstatic LRESULT CALLBACK\nWindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)\n{\n    switch (msg)\n    {\n    case WM_DESTROY:\n        PostQuitMessage(0);\n        return 0;\n    }\n\n    if (nk_gdi_handle_event(wnd, msg, wparam, lparam))\n        return 0;\n\n    return DefWindowProcW(wnd, msg, wparam, lparam);\n}\n\nint main(void)\n{\n    GdiFont* font;\n    struct nk_context *ctx;\n\n    WNDCLASSW wc;\n    ATOM atom;\n    RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };\n    DWORD style = WS_OVERLAPPEDWINDOW;\n    DWORD exstyle = WS_EX_APPWINDOW;\n    HWND wnd;\n    HDC dc;\n    int running = 1;\n    int needs_refresh = 1;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    /* Win32 */\n    memset(&wc, 0, sizeof(wc));\n    wc.style = CS_DBLCLKS;\n    wc.lpfnWndProc = WindowProc;\n    wc.hInstance = GetModuleHandleW(0);\n    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);\n    wc.hCursor = LoadCursor(NULL, IDC_ARROW);\n    wc.lpszClassName = L\"NuklearWindowClass\";\n    atom = RegisterClassW(&wc);\n\n    AdjustWindowRectEx(&rect, style, FALSE, exstyle);\n    wnd = CreateWindowExW(exstyle, wc.lpszClassName, L\"Nuklear GDI Demo\",\n        style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,\n        rect.right - rect.left, rect.bottom - rect.top,\n        NULL, NULL, wc.hInstance, NULL);\n    dc = GetDC(wnd);\n\n    /* GUI */\n    font = nk_gdifont_create(\"Arial\", 14);\n    ctx = nk_gdi_init(font, dc, WINDOW_WIDTH, WINDOW_HEIGHT);\n\n    while (running)\n    {\n        /* Input */\n        MSG msg;\n        nk_input_begin(ctx);\n        if (needs_refresh == 0) {\n            if (GetMessageW(&msg, NULL, 0, 0) <= 0)\n                running = 0;\n            else {\n                TranslateMessage(&msg);\n                DispatchMessageW(&msg);\n            }\n            needs_refresh = 1;\n        } else needs_refresh = 0;\n\n        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {\n            if (msg.message == WM_QUIT)\n                running = 0;\n            TranslateMessage(&msg);\n            DispatchMessageW(&msg);\n            needs_refresh = 1;\n        }\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 200, 200),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 22, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        nk_gdi_render(nk_rgb(30,30,30));\n    }\n\n    nk_gdifont_del(font);\n    ReleaseDC(wnd, dc);\n    UnregisterClassW(wc.lpszClassName, wc.hInstance);\n    return 0;\n}\n\n"
  },
  {
    "path": "demo/gdi/nuklear_gdi.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_GDI_H_\n#define NK_GDI_H_\n\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <wingdi.h>\n\ntypedef struct GdiFont GdiFont;\nNK_API struct nk_context* nk_gdi_init(GdiFont *font, HDC window_dc, unsigned int width, unsigned int height);\nNK_API int nk_gdi_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);\nNK_API void nk_gdi_render(struct nk_color clear);\nNK_API void nk_gdi_shutdown(void);\n\n/* font */\nNK_API GdiFont* nk_gdifont_create(const char *name, int size);\nNK_API void nk_gdifont_del(GdiFont *font);\nNK_API void nk_gdi_set_font(GdiFont *font);\n\n#endif\n\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_GDI_IMPLEMENTATION\n#include <string.h>\n#include <stdlib.h>\n#include <malloc.h>\n\nstruct GdiFont {\n    struct nk_user_font nk;\n    int height;\n    HFONT handle;\n    HDC dc;\n};\n\nstatic struct {\n    HBITMAP bitmap;\n    HDC window_dc;\n    HDC memory_dc;\n    unsigned int width;\n    unsigned int height;\n    struct nk_context ctx;\n} gdi;\n\nstatic void\nnk_create_image(struct nk_image * image, const char * frame_buffer, const int width, const int height)\n{\n    if (image && frame_buffer && (width > 0) && (height > 0))\n    {\n        const unsigned char * src = (const unsigned char *)frame_buffer;\n        INT row = ((width * 3 + 3) & ~3);\n        LPBYTE lpBuf, pb = NULL;\n        BITMAPINFO bi = { 0 };\n        HBITMAP hbm;\n        int v, i;\n\n        image->w = width;\n        image->h = height;\n        image->region[0] = 0;\n        image->region[1] = 0;\n        image->region[2] = width;\n        image->region[3] = height;\n\n        bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\n        bi.bmiHeader.biWidth = width;\n        bi.bmiHeader.biHeight = height;\n        bi.bmiHeader.biPlanes = 1;\n        bi.bmiHeader.biBitCount = 24;\n        bi.bmiHeader.biCompression = BI_RGB;\n        bi.bmiHeader.biSizeImage = row * height;\n\n        hbm = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, (void**)&lpBuf, NULL, 0);\n\n        pb = lpBuf + row * height;\n        for (v = 0; v < height; v++)\n        {\n            pb -= row;\n            for (i = 0; i < row; i += 3)\n            {\n                pb[i + 0] = src[0];\n                pb[i + 1] = src[1];\n                pb[i + 2] = src[2];\n                src += 3;\n            }\n        }\n        SetDIBits(NULL, hbm, 0, height, lpBuf, &bi, DIB_RGB_COLORS);\n        image->handle.ptr = hbm;\n    }\n}\n\nstatic void\nnk_delete_image(struct nk_image * image)\n{\n    if (image && image->handle.id != 0)\n    {\n        HBITMAP hbm = (HBITMAP)image->handle.ptr;\n        DeleteObject(hbm);\n        memset(image, 0, sizeof(struct nk_image));\n    }\n}\n\nstatic void\nnk_gdi_draw_image(short x, short y, unsigned short w, unsigned short h,\n    struct nk_image img, struct nk_color col)\n{\n    HBITMAP hbm = (HBITMAP)img.handle.ptr;\n    HDC     hDCBits;\n    BITMAP  bitmap;\n\n    if (!gdi.memory_dc || !hbm)\n        return;\n\n    hDCBits = CreateCompatibleDC(gdi.memory_dc);\n    GetObject(hbm, sizeof(BITMAP), (LPSTR)&bitmap);\n    SelectObject(hDCBits, hbm);\n    StretchBlt(gdi.memory_dc, x, y, w, h, hDCBits, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);\n    DeleteDC(hDCBits);\n}\n\nstatic COLORREF\nconvert_color(struct nk_color c)\n{\n    return c.r | (c.g << 8) | (c.b << 16);\n}\n\nstatic void\nnk_gdi_scissor(HDC dc, float x, float y, float w, float h)\n{\n    SelectClipRgn(dc, NULL);\n    IntersectClipRect(dc, (int)x, (int)y, (int)(x + w + 1), (int)(y + h + 1));\n}\n\nstatic void\nnk_gdi_stroke_line(HDC dc, short x0, short y0, short x1,\n    short y1, unsigned int line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n\n    HPEN pen = NULL;\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    } else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    MoveToEx(dc, x0, y0, NULL);\n    LineTo(dc, x1, y1);\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_stroke_rect(HDC dc, short x, short y, unsigned short w,\n    unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    HGDIOBJ br;\n    HPEN pen = NULL;\n\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    } else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    br = SelectObject(dc, GetStockObject(NULL_BRUSH));\n    if (r == 0) {\n        Rectangle(dc, x, y, x + w, y + h);\n    } else {\n        RoundRect(dc, x, y, x + w, y + h, r, r);\n    }\n    SelectObject(dc, br);\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_fill_rect(HDC dc, short x, short y, unsigned short w,\n    unsigned short h, unsigned short r, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n\n    if (r == 0) {\n        RECT rect;\n        SetRect(&rect, x, y, x + w, y + h);\n        SetBkColor(dc, color);\n        ExtTextOutW(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);\n    } else {\n        SetDCPenColor(dc, color);\n        SetDCBrushColor(dc, color);\n        RoundRect(dc, x, y, x + w, y + h, r, r);\n    }\n}\nstatic void\nnk_gdi_set_vertexColor(PTRIVERTEX tri, struct nk_color col)\n{\n    tri->Red   = col.r << 8;\n    tri->Green = col.g << 8;\n    tri->Blue  = col.b << 8;\n    tri->Alpha = 0xff << 8;\n}\n\nstatic void\nnk_gdi_rect_multi_color(HDC dc, short x, short y, unsigned short w,\n    unsigned short h, struct nk_color left, struct nk_color top,\n    struct nk_color right, struct nk_color bottom)\n{\n    BLENDFUNCTION alphaFunction;\n    GRADIENT_RECT gRect;\n    GRADIENT_TRIANGLE gTri[2];\n    TRIVERTEX vt[4];\n    alphaFunction.BlendOp = AC_SRC_OVER;\n    alphaFunction.BlendFlags = 0;\n    alphaFunction.SourceConstantAlpha = 0;\n    alphaFunction.AlphaFormat = AC_SRC_ALPHA;\n\n    /* TODO: This Case Needs Repair.*/\n    /* Top Left Corner */\n    vt[0].x     = x;\n    vt[0].y     = y;\n    nk_gdi_set_vertexColor(&vt[0], left);\n    /* Top Right Corner */\n    vt[1].x     = x+w;\n    vt[1].y     = y;\n    nk_gdi_set_vertexColor(&vt[1], top);\n    /* Bottom Left Corner */\n    vt[2].x     = x;\n    vt[2].y     = y+h;\n    nk_gdi_set_vertexColor(&vt[2], right);\n\n    /* Bottom Right Corner */\n    vt[3].x     = x+w;\n    vt[3].y     = y+h;\n    nk_gdi_set_vertexColor(&vt[3], bottom);\n\n    gTri[0].Vertex1 = 0;\n    gTri[0].Vertex2 = 1;\n    gTri[0].Vertex3 = 2;\n    gTri[1].Vertex1 = 2;\n    gTri[1].Vertex2 = 1;\n    gTri[1].Vertex3 = 3;\n    GdiGradientFill(dc, vt, 4, gTri, 2 , GRADIENT_FILL_TRIANGLE);\n    AlphaBlend(gdi.window_dc,  x, y, x+w, y+h,gdi.memory_dc, x, y, x+w, y+h,alphaFunction);\n\n}\n\nstatic BOOL\nSetPoint(POINT *p, LONG x, LONG y)\n{\n    if (!p)\n        return FALSE;\n    p->x = x;\n    p->y = y;\n    return TRUE;\n}\n\nstatic void\nnk_gdi_fill_triangle(HDC dc, short x0, short y0, short x1,\n    short y1, short x2, short y2, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    POINT points[3];\n\n    SetPoint(&points[0], x0, y0);\n    SetPoint(&points[1], x1, y1);\n    SetPoint(&points[2], x2, y2);\n\n    SetDCPenColor(dc, color);\n    SetDCBrushColor(dc, color);\n    Polygon(dc, points, 3);\n}\n\nstatic void\nnk_gdi_stroke_triangle(HDC dc, short x0, short y0, short x1,\n    short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    POINT points[4];\n    HPEN pen = NULL;\n\n    SetPoint(&points[0], x0, y0);\n    SetPoint(&points[1], x1, y1);\n    SetPoint(&points[2], x2, y2);\n    SetPoint(&points[3], x0, y0);\n\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    } else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    Polyline(dc, points, 4);\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_fill_polygon(HDC dc, const struct nk_vec2i *pnts, int count, struct nk_color col)\n{\n    int i = 0;\n    #define MAX_POINTS 64\n    POINT points[MAX_POINTS];\n    COLORREF color = convert_color(col);\n    SetDCBrushColor(dc, color);\n    SetDCPenColor(dc, color);\n    for (i = 0; i < count && i < MAX_POINTS; ++i) {\n        points[i].x = pnts[i].x;\n        points[i].y = pnts[i].y;\n    }\n    Polygon(dc, points, i);\n    #undef MAX_POINTS\n}\n\nstatic void\nnk_gdi_stroke_polygon(HDC dc, const struct nk_vec2i *pnts, int count,\n    unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    HPEN pen = NULL;\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    } else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    if (count > 0) {\n        int i;\n        MoveToEx(dc, pnts[0].x, pnts[0].y, NULL);\n        for (i = 1; i < count; ++i)\n            LineTo(dc, pnts[i].x, pnts[i].y);\n        LineTo(dc, pnts[0].x, pnts[0].y);\n    }\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_stroke_polyline(HDC dc, const struct nk_vec2i *pnts,\n    int count, unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    HPEN pen = NULL;\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    } else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    if (count > 0) {\n        int i;\n        MoveToEx(dc, pnts[0].x, pnts[0].y, NULL);\n        for (i = 1; i < count; ++i)\n            LineTo(dc, pnts[i].x, pnts[i].y);\n    }\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_stroke_arc(HDC dc, short cx, short cy, unsigned short r, float amin, float adelta, unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n\n    /* setup pen */\n    HPEN pen = NULL;\n    if (line_thickness == 1)\n        SetDCPenColor(dc, color);\n    else\n    {\n        /* the flat endcap makes thick arcs look better */\n        DWORD pen_style = PS_SOLID | PS_ENDCAP_FLAT | PS_GEOMETRIC;\n\n        LOGBRUSH brush;\n        brush.lbStyle = BS_SOLID;\n        brush.lbColor = color;\n        brush.lbHatch = 0;\n\n        pen = ExtCreatePen(pen_style, line_thickness, &brush, 0, NULL);\n        SelectObject(dc, pen);\n    }\n\n    /* calculate arc and draw */\n    int start_x = cx + (int) ((float)r*nk_cos(amin+adelta)),\n        start_y = cy + (int) ((float)r*nk_sin(amin+adelta)),\n        end_x = cx + (int) ((float)r*nk_cos(amin)),\n        end_y = cy + (int) ((float)r*nk_sin(amin));\n\n    HGDIOBJ br = SelectObject(dc, GetStockObject(NULL_BRUSH));\n    SetArcDirection(dc, AD_COUNTERCLOCKWISE);\n    Pie(dc, cx-r, cy-r, cx+r, cy+r, start_x, start_y, end_x, end_y);\n    SelectObject(dc, br);\n\n    if (pen)\n    {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_fill_arc(HDC dc, short cx, short cy, unsigned short r, float amin, float adelta, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    SetDCBrushColor(dc, color);\n    SetDCPenColor(dc, color);\n\n    int start_x = cx + (int) ((float)r*nk_cos(amin+adelta)),\n        start_y = cy + (int) ((float)r*nk_sin(amin+adelta)),\n        end_x = cx + (int) ((float)r*nk_cos(amin)),\n        end_y = cy + (int) ((float)r*nk_sin(amin));\n\n    Pie(dc, cx-r, cy-r, cx+r, cy+r, start_x, start_y, end_x, end_y);\n}\n\nstatic void\nnk_gdi_fill_circle(HDC dc, short x, short y, unsigned short w,\n    unsigned short h, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    SetDCBrushColor(dc, color);\n    SetDCPenColor(dc, color);\n    Ellipse(dc, x, y, x + w, y + h);\n}\n\nstatic void\nnk_gdi_stroke_circle(HDC dc, short x, short y, unsigned short w,\n    unsigned short h, unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    HPEN pen = NULL;\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    } else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    HGDIOBJ br = SelectObject(dc, GetStockObject(NULL_BRUSH));\n    SetDCBrushColor(dc, OPAQUE);\n    Ellipse(dc, x, y, x + w, y + h);\n    SelectObject(dc, br);\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_stroke_curve(HDC dc, struct nk_vec2i p1,\n    struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,\n    unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    POINT p[4];\n    HPEN pen = NULL;\n\n    SetPoint(&p[0], p1.x, p1.y);\n    SetPoint(&p[1], p2.x, p2.y);\n    SetPoint(&p[2], p3.x, p3.y);\n    SetPoint(&p[3], p4.x, p4.y);\n\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    } else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    SetDCBrushColor(dc, OPAQUE);\n    PolyBezier(dc, p, 4);\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_draw_text(HDC dc, short x, short y, unsigned short w, unsigned short h,\n    const char *text, int len, GdiFont *font, struct nk_color cbg, struct nk_color cfg)\n{\n    int wsize;\n    WCHAR* wstr;\n\n    if(!text || !font || !len) return;\n\n    wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);\n    wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));\n    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);\n\n    SetBkMode(dc, TRANSPARENT); /* Transparent Text Background */\n    SetBkColor(dc, convert_color(cbg));\n    SetTextColor(dc, convert_color(cfg));\n\n    SelectObject(dc, font->handle);\n    ExtTextOutW(dc, x, y, ETO_OPAQUE, NULL, wstr, wsize, NULL);\n}\n\nstatic void\nnk_gdi_clear(HDC dc, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    RECT rect;\n    SetRect(&rect, 0, 0, gdi.width, gdi.height);\n    SetBkColor(dc, color);\n\n    ExtTextOutW(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);\n}\n\nstatic void\nnk_gdi_blit(HDC dc)\n{\n    BitBlt(dc, 0, 0, gdi.width, gdi.height, gdi.memory_dc, 0, 0, SRCCOPY);\n\n}\n\nGdiFont*\nnk_gdifont_create(const char *name, int size)\n{\n    TEXTMETRICW metric;\n    GdiFont *font = (GdiFont*)calloc(1, sizeof(GdiFont));\n    if (!font)\n        return NULL;\n    font->dc = CreateCompatibleDC(0);\n    font->handle = CreateFontA(size, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, name);\n    SelectObject(font->dc, font->handle);\n    GetTextMetricsW(font->dc, &metric);\n    font->height = metric.tmHeight;\n    return font;\n}\n\nstatic float\nnk_gdifont_get_text_width(nk_handle handle, float height, const char *text, int len)\n{\n    GdiFont *font = (GdiFont*)handle.ptr;\n    SIZE size;\n    int wsize;\n    WCHAR* wstr;\n    if (!font || !text)\n        return 0;\n\n    wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);\n    wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));\n    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);\n    if (GetTextExtentPoint32W(font->dc, wstr, wsize, &size))\n        return (float)size.cx;\n    return -1.0f;\n}\n\nvoid\nnk_gdifont_del(GdiFont *font)\n{\n    if(!font) return;\n    DeleteObject(font->handle);\n    DeleteDC(font->dc);\n    free(font);\n}\n\nstatic void\nnk_gdi_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    (void)usr;\n    if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))\n    {\n        HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);\n        if (mem)\n        {\n            SIZE_T size = GlobalSize(mem) - 1;\n            if (size)\n            {\n                LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);\n                if (wstr)\n                {\n                    int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), NULL, 0, NULL, NULL);\n                    if (utf8size)\n                    {\n                        char* utf8 = (char*)malloc(utf8size);\n                        if (utf8)\n                        {\n                            WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), utf8, utf8size, NULL, NULL);\n                            nk_textedit_paste(edit, utf8, utf8size);\n                            free(utf8);\n                        }\n                    }\n                    GlobalUnlock(mem);\n                }\n            }\n        }\n        CloseClipboard();\n    }\n}\n\nstatic void\nnk_gdi_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    if (OpenClipboard(NULL))\n    {\n        int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);\n        if (wsize)\n        {\n            HGLOBAL mem = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));\n            if (mem)\n            {\n                wchar_t* wstr = (wchar_t*)GlobalLock(mem);\n                if (wstr)\n                {\n                    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);\n                    wstr[wsize] = 0;\n                    GlobalUnlock(mem);\n\n                    SetClipboardData(CF_UNICODETEXT, mem);\n                }\n            }\n        }\n        CloseClipboard();\n    }\n}\n\nNK_API struct nk_context*\nnk_gdi_init(GdiFont *gdifont, HDC window_dc, unsigned int width, unsigned int height)\n{\n    struct nk_user_font *font = &gdifont->nk;\n    font->userdata = nk_handle_ptr(gdifont);\n    font->height = (float)gdifont->height;\n    font->width = nk_gdifont_get_text_width;\n\n    gdi.bitmap = CreateCompatibleBitmap(window_dc, width, height);\n    gdi.window_dc = window_dc;\n    gdi.memory_dc = CreateCompatibleDC(window_dc);\n    gdi.width = width;\n    gdi.height = height;\n    SelectObject(gdi.memory_dc, gdi.bitmap);\n\n    nk_init_default(&gdi.ctx, font);\n    gdi.ctx.clip.copy = nk_gdi_clipboard_copy;\n    gdi.ctx.clip.paste = nk_gdi_clipboard_paste;\n    return &gdi.ctx;\n}\n\nNK_API void\nnk_gdi_set_font(GdiFont *gdifont)\n{\n    struct nk_user_font *font = &gdifont->nk;\n    font->userdata = nk_handle_ptr(gdifont);\n    font->height = (float)gdifont->height;\n    font->width = nk_gdifont_get_text_width;\n    nk_style_set_font(&gdi.ctx, font);\n}\n\nNK_API int\nnk_gdi_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)\n{\n    static int insert_toggle = 0;\n    switch (msg)\n    {\n    case WM_SIZE:\n    {\n        unsigned width = LOWORD(lparam);\n        unsigned height = HIWORD(lparam);\n        if (width != gdi.width || height != gdi.height)\n        {\n            DeleteObject(gdi.bitmap);\n            gdi.bitmap = CreateCompatibleBitmap(gdi.window_dc, width, height);\n            gdi.width = width;\n            gdi.height = height;\n            SelectObject(gdi.memory_dc, gdi.bitmap);\n        }\n        break;\n    }\n\n    case WM_PAINT:\n    {\n        PAINTSTRUCT paint;\n        HDC dc = BeginPaint(wnd, &paint);\n        nk_gdi_blit(dc);\n        EndPaint(wnd, &paint);\n        return 1;\n    }\n\n    case WM_KEYDOWN:\n    case WM_KEYUP:\n    case WM_SYSKEYDOWN:\n    case WM_SYSKEYUP:\n    {\n        int down = !((lparam >> 31) & 1);\n        int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);\n\n        switch (wparam)\n        {\n        case VK_SHIFT:\n        case VK_LSHIFT:\n        case VK_RSHIFT:\n            nk_input_key(&gdi.ctx, NK_KEY_SHIFT, down);\n            return 1;\n\n        case VK_DELETE:\n            nk_input_key(&gdi.ctx, NK_KEY_DEL, down);\n            return 1;\n\n        case VK_RETURN:\n        case VK_SEPARATOR:\n            nk_input_key(&gdi.ctx, NK_KEY_ENTER, down);\n            return 1;\n\n        case VK_TAB:\n            nk_input_key(&gdi.ctx, NK_KEY_TAB, down);\n            return 1;\n\n        case VK_LEFT:\n            if (ctrl)\n                nk_input_key(&gdi.ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else\n                nk_input_key(&gdi.ctx, NK_KEY_LEFT, down);\n            return 1;\n\n        case VK_RIGHT:\n            if (ctrl)\n                nk_input_key(&gdi.ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else\n                nk_input_key(&gdi.ctx, NK_KEY_RIGHT, down);\n            return 1;\n\n        case VK_BACK:\n            nk_input_key(&gdi.ctx, NK_KEY_BACKSPACE, down);\n            return 1;\n\n        case VK_HOME:\n            nk_input_key(&gdi.ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(&gdi.ctx, NK_KEY_SCROLL_START, down);\n            return 1;\n\n        case VK_END:\n            nk_input_key(&gdi.ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(&gdi.ctx, NK_KEY_SCROLL_END, down);\n            return 1;\n\n        case VK_NEXT:\n            nk_input_key(&gdi.ctx, NK_KEY_SCROLL_DOWN, down);\n            return 1;\n\n        case VK_PRIOR:\n            nk_input_key(&gdi.ctx, NK_KEY_SCROLL_UP, down);\n            return 1;\n\n        case VK_ESCAPE:\n            nk_input_key(&gdi.ctx, NK_KEY_TEXT_RESET_MODE, down);\n            return 1;\n\n        case VK_INSERT:\n        /* Only switch on release to avoid repeat issues\n         * kind of confusing since we have to negate it but we're already\n         * hacking it since Nuklear treats them as two separate keys rather\n         * than a single toggle state */\n            if (!down) {\n                insert_toggle = !insert_toggle;\n                if (insert_toggle) {\n                    nk_input_key(&gdi.ctx, NK_KEY_TEXT_INSERT_MODE, !down);\n                    /* nk_input_key(&gdi.ctx, NK_KEY_TEXT_REPLACE_MODE, down); */\n                } else {\n                    nk_input_key(&gdi.ctx, NK_KEY_TEXT_REPLACE_MODE, !down);\n                    /* nk_input_key(&gdi.ctx, NK_KEY_TEXT_INSERT_MODE, down); */\n                }\n            }\n            return 1;\n\n        case 'A':\n            if (ctrl) {\n                nk_input_key(&gdi.ctx, NK_KEY_TEXT_SELECT_ALL, down);\n                return 1;\n            }\n            break;\n\n        case 'B':\n            if (ctrl) {\n                nk_input_key(&gdi.ctx, NK_KEY_TEXT_LINE_START, down);\n                return 1;\n            }\n            break;\n\n        case 'E':\n            if (ctrl) {\n                nk_input_key(&gdi.ctx, NK_KEY_TEXT_LINE_END, down);\n                return 1;\n            }\n            break;\n\n        case 'C':\n            if (ctrl) {\n                nk_input_key(&gdi.ctx, NK_KEY_COPY, down);\n                return 1;\n            }\n            break;\n\n        case 'V':\n            if (ctrl) {\n                nk_input_key(&gdi.ctx, NK_KEY_PASTE, down);\n                return 1;\n            }\n            break;\n\n        case 'X':\n            if (ctrl) {\n                nk_input_key(&gdi.ctx, NK_KEY_CUT, down);\n                return 1;\n            }\n            break;\n\n        case 'Z':\n            if (ctrl) {\n                nk_input_key(&gdi.ctx, NK_KEY_TEXT_UNDO, down);\n                return 1;\n            }\n            break;\n\n        case 'R':\n            if (ctrl) {\n                nk_input_key(&gdi.ctx, NK_KEY_TEXT_REDO, down);\n                return 1;\n            }\n            break;\n        }\n        return 0;\n    }\n\n    case WM_CHAR:\n        if (wparam >= 32)\n        {\n            nk_input_unicode(&gdi.ctx, (nk_rune)wparam);\n            return 1;\n        }\n        break;\n\n    case WM_LBUTTONDOWN:\n        nk_input_button(&gdi.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_LBUTTONUP:\n        nk_input_button(&gdi.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        nk_input_button(&gdi.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_RBUTTONDOWN:\n        nk_input_button(&gdi.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_RBUTTONUP:\n        nk_input_button(&gdi.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_MBUTTONDOWN:\n        nk_input_button(&gdi.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_MBUTTONUP:\n        nk_input_button(&gdi.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_XBUTTONDOWN:\n        switch (GET_XBUTTON_WPARAM(wparam)) {\n        case XBUTTON1:\n            nk_input_button(&gdi.ctx, NK_BUTTON_X1, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n            break;\n        case XBUTTON2:\n            nk_input_button(&gdi.ctx, NK_BUTTON_X2, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n            break;\n        }\n        SetCapture(wnd);\n        return 1;\n\n    case WM_XBUTTONUP:\n        switch (GET_XBUTTON_WPARAM(wparam)) {\n        case XBUTTON1:\n            nk_input_button(&gdi.ctx, NK_BUTTON_X1, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n            break;\n        case XBUTTON2:\n            nk_input_button(&gdi.ctx, NK_BUTTON_X2, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n            break;\n        }\n        ReleaseCapture();\n        return 1;\n\n    case WM_MOUSEWHEEL:\n        nk_input_scroll(&gdi.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));\n        return 1;\n\n    case WM_MOUSEMOVE:\n        nk_input_motion(&gdi.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));\n        return 1;\n\n    case WM_LBUTTONDBLCLK:\n        nk_input_button(&gdi.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        return 1;\n    }\n\n    return 0;\n}\n\nNK_API void\nnk_gdi_shutdown(void)\n{\n    DeleteObject(gdi.memory_dc);\n    DeleteObject(gdi.bitmap);\n    nk_free(&gdi.ctx);\n}\n\nNK_API void\nnk_gdi_render(struct nk_color clear)\n{\n    const struct nk_command *cmd;\n\n    HDC memory_dc = gdi.memory_dc;\n    SelectObject(memory_dc, GetStockObject(DC_PEN));\n    SelectObject(memory_dc, GetStockObject(DC_BRUSH));\n    nk_gdi_clear(memory_dc, clear);\n\n    nk_foreach(cmd, &gdi.ctx)\n    {\n        switch (cmd->type) {\n        case NK_COMMAND_NOP: break;\n        case NK_COMMAND_SCISSOR: {\n            const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;\n            nk_gdi_scissor(memory_dc, s->x, s->y, s->w, s->h);\n        } break;\n        case NK_COMMAND_LINE: {\n            const struct nk_command_line *l = (const struct nk_command_line *)cmd;\n            nk_gdi_stroke_line(memory_dc, l->begin.x, l->begin.y, l->end.x,\n                l->end.y, l->line_thickness, l->color);\n        } break;\n        case NK_COMMAND_RECT: {\n            const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;\n            nk_gdi_stroke_rect(memory_dc, r->x, r->y, r->w, r->h,\n                (unsigned short)r->rounding, r->line_thickness, r->color);\n        } break;\n        case NK_COMMAND_RECT_FILLED: {\n            const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;\n            nk_gdi_fill_rect(memory_dc, r->x, r->y, r->w, r->h,\n                (unsigned short)r->rounding, r->color);\n        } break;\n        case NK_COMMAND_CIRCLE: {\n            const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;\n            nk_gdi_stroke_circle(memory_dc, c->x, c->y, c->w, c->h, c->line_thickness, c->color);\n        } break;\n        case NK_COMMAND_CIRCLE_FILLED: {\n            const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;\n            nk_gdi_fill_circle(memory_dc, c->x, c->y, c->w, c->h, c->color);\n        } break;\n        case NK_COMMAND_ARC: {\n            const struct nk_command_arc *q = (const struct nk_command_arc *)cmd;\n            nk_gdi_stroke_arc(memory_dc, q->cx, q->cy, q->r, q->a[0], q->a[1], q->line_thickness, q->color);\n        } break;\n        case NK_COMMAND_ARC_FILLED: {\n            const struct nk_command_arc_filled *q = (const struct nk_command_arc_filled *)cmd;\n            nk_gdi_fill_arc(memory_dc, q->cx, q->cy, q->r, q->a[0], q->a[1], q->color);\n        } break;\n        case NK_COMMAND_TRIANGLE: {\n            const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;\n            nk_gdi_stroke_triangle(memory_dc, t->a.x, t->a.y, t->b.x, t->b.y,\n                t->c.x, t->c.y, t->line_thickness, t->color);\n        } break;\n        case NK_COMMAND_TRIANGLE_FILLED: {\n            const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;\n            nk_gdi_fill_triangle(memory_dc, t->a.x, t->a.y, t->b.x, t->b.y,\n                t->c.x, t->c.y, t->color);\n        } break;\n        case NK_COMMAND_POLYGON: {\n            const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd;\n            nk_gdi_stroke_polygon(memory_dc, p->points, p->point_count, p->line_thickness,p->color);\n        } break;\n        case NK_COMMAND_POLYGON_FILLED: {\n            const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;\n            nk_gdi_fill_polygon(memory_dc, p->points, p->point_count, p->color);\n        } break;\n        case NK_COMMAND_POLYLINE: {\n            const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;\n            nk_gdi_stroke_polyline(memory_dc, p->points, p->point_count, p->line_thickness, p->color);\n        } break;\n        case NK_COMMAND_TEXT: {\n            const struct nk_command_text *t = (const struct nk_command_text*)cmd;\n            nk_gdi_draw_text(memory_dc, t->x, t->y, t->w, t->h,\n                (const char*)t->string, t->length,\n                (GdiFont*)t->font->userdata.ptr,\n                t->background, t->foreground);\n        } break;\n        case NK_COMMAND_CURVE: {\n            const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;\n            nk_gdi_stroke_curve(memory_dc, q->begin, q->ctrl[0], q->ctrl[1],\n                q->end, q->line_thickness, q->color);\n        } break;\n        case NK_COMMAND_RECT_MULTI_COLOR: {\n            const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color *)cmd;\n            nk_gdi_rect_multi_color(memory_dc, r->x, r->y,r->w, r->h, r->left, r->top, r->right, r->bottom);\n        } break;\n        case NK_COMMAND_IMAGE: {\n            const struct nk_command_image *i = (const struct nk_command_image *)cmd;\n            nk_gdi_draw_image(i->x, i->y, i->w, i->h, i->img, i->col);\n        } break;\n        case NK_COMMAND_CUSTOM:\n        default: break;\n        }\n    }\n    nk_gdi_blit(gdi.window_dc);\n    nk_clear(&gdi.ctx);\n}\n\n#endif\n\n"
  },
  {
    "path": "demo/gdi_native_nuklear/build.bat",
    "content": "@echo off\n\nrem This will use VS2015 for compiler\ncall \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat\" x86\n\ncl /nologo /W3 /O2 /fp:fast /Gm- /D_CRT_SECURE_NO_DEPRECATE /Fedemo.exe main.c user32.lib gdi32.lib Msimg32.lib /link /incremental:no \n"
  },
  {
    "path": "demo/gdi_native_nuklear/main.c",
    "content": "#include <windows.h>\n\n#pragma comment(linker,\"\\\"/manifestdependency:type='win32' \\\nname='Microsoft.Windows.Common-Controls' version='6.0.0.0' \\\nprocessorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n\n/* Includes the default nuklear implementation\n * Includes the modified GDI backend (No more global state to allow multiple hwnd's)\n */ \n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_IMPLEMENTATION\n#define NK_GDI_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_gdi.h\"\n\n/* Include the window framework (the new fancy code of this demo) */\n#define NKGDI_IMPLEMENT_WINDOW\n#include \"window.h\"\n\n/* This callback will be called when the window is draw \n * You will NOT need to call nk_begin(...) and nk_end(...)\n * begin and end are handled by the parent code calling this\n * callback\n */\nint drawCallback(struct nk_context* ctx)\n{\n    /* Code is from ../calculator.c */\n    static int set = 0, prev = 0, op = 0;\n    static const char numbers[] = \"789456123\";\n    static const char ops[] = \"+-*/\";\n    static double a = 0, b = 0;\n    static double *current = &a;\n\n    size_t i = 0;\n    int solve = 0;\n    {int len; char buffer[256];\n    nk_layout_row_dynamic(ctx, 35, 1);\n    len = snprintf(buffer, 256, \"%.2f\", *current);\n    nk_edit_string(ctx, NK_EDIT_SIMPLE, buffer, &len, 255, nk_filter_float);\n    buffer[len] = 0;\n    *current = atof(buffer);}\n\n    nk_layout_row_dynamic(ctx, 35, 4);\n    for (i = 0; i < 16; ++i) {\n        if (i >= 12 && i < 15) {\n            if (i > 12) continue;\n            if (nk_button_label(ctx, \"C\")) {\n                a = b = op = 0; current = &a; set = 0;\n            } if (nk_button_label(ctx, \"0\")) {\n                *current = *current*10.0f; set = 0;\n            } if (nk_button_label(ctx, \"=\")) {\n                solve = 1; prev = op; op = 0;\n            }\n        } else if (((i+1) % 4)) {\n            if (nk_button_text(ctx, &numbers[(i/4)*3+i%4], 1)) {\n                *current = *current * 10.0f + numbers[(i/4)*3+i%4] - '0';\n                set = 0;\n            }\n        } else if (nk_button_text(ctx, &ops[i/4], 1)) {\n            if (!set) {\n                if (current != &b) {\n                    current = &b;\n                } else {\n                    prev = op;\n                    solve = 1;\n                }\n            }\n            op = ops[i/4];\n            set = 1;\n        }\n    }\n    if (solve) {\n        if (prev == '+') a = a + b;\n        if (prev == '-') a = a - b;\n        if (prev == '*') a = a * b;\n        if (prev == '/') a = a / b;\n        current = &a;\n        if (set) current = &b;\n        b = 0; set = 0;\n    }\n    return 1;\n}\n\n/* Main entry point - wWinMain used for UNICODE\n * (You can also use _tWinMain(...) to automaticaly use the ASCII or WIDE char entry point base on your build)  \n */\nINT WINAPI wWinMain(HINSTANCE _In_ hInstance, HINSTANCE _In_opt_ hPrevInstance, PWSTR _In_ cmdArgs, INT _In_ cmdShow)\n{\n    /* Call this first to setup all required prerequisites */\n    nkgdi_window_init();\n\t\n    /* Preparing two window contexts */\n    struct nkgdi_window w1, w2;\n    memset(&w1, 0x0, sizeof(struct nkgdi_window));\n    memset(&w2, 0x0, sizeof(struct nkgdi_window));\n\t\n    /* Configure and create window 1. \n     * Note: You can allways change the direct accesible parameters later as well! \n     */\n    w1.allow_sizing = 0;\n    w1.allow_maximize = 0;\n    w1.allow_move = 0;\n    w1.has_titlebar = 0;\n    w1.cb_on_draw = &drawCallback;\n    nkgdi_window_create(&w1, 500, 500, \"F1\", 10, 10);\n\n    /* Configure and create window 2 */\n    w2.allow_sizing = 1;\n    w2.allow_maximize = 1;\n    w2.allow_move = 1;\n    w2.has_titlebar = 1;\n    w2.cb_on_draw = &drawCallback;\n    nkgdi_window_create(&w2, 500, 500, \"F2\", 520, 10);\n    \n    /* As long as both windows are valid (nkgdi_window_update returning 1) */\n    while (nkgdi_window_update(&w1) && nkgdi_window_update(&w2)) Sleep(20);\n\n    /* Destroy both windows context */\n    nkgdi_window_destroy(&w1);\n    nkgdi_window_destroy(&w2);\n\n    /* Call nkgdi_window_shutdown to properly shutdown the gdi window framework */\n    nkgdi_window_shutdown();\n    return 0;\n}\n"
  },
  {
    "path": "demo/gdi_native_nuklear/nuklear_gdi.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n *\n * Modified GDI backend 2022\n * Now based on a context that is required for each API function call.\n * Removes the global state --> you can have multiple windows :-)\n *\n */\n /*\n  * ==============================================================\n  *\n  *                              API\n  *\n  * ===============================================================\n  */\n#ifndef NK_GDI_H_\n#define NK_GDI_H_\n\n#ifdef __cplusplus\nextern \"C\"{\n#endif\n\ntypedef struct GdiFont GdiFont;\nstruct _nk_gdi_ctx;\ntypedef struct _nk_gdi_ctx* nk_gdi_ctx;\n\nNK_API struct nk_context* nk_gdi_init(nk_gdi_ctx* gdi, GdiFont* font, HDC window_dc, unsigned int width, unsigned int height);\nNK_API int nk_gdi_handle_event(nk_gdi_ctx gdi, HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);\nNK_API void nk_gdi_render(nk_gdi_ctx gdi, struct nk_color clear);\nNK_API void nk_gdi_shutdown(nk_gdi_ctx gdi);\n\n/* font */\nNK_API GdiFont* nk_gdifont_create(const char* name, int size);\nNK_API void nk_gdifont_del(GdiFont* font);\nNK_API void nk_gdi_set_font(nk_gdi_ctx gdi, GdiFont* font);\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_GDI_IMPLEMENTATION\n#include <string.h>\n#include <stdlib.h>\n#include <malloc.h>\n\nstruct GdiFont {\n    struct nk_user_font nk;\n    int height;\n    HFONT handle;\n    HDC dc;\n};\n\nstruct _nk_gdi_ctx {\n    HBITMAP bitmap;\n    HDC window_dc;\n    HDC memory_dc;\n    unsigned int width;\n    unsigned int height;\n    struct nk_context ctx;\n};\n\nstatic void\nnk_create_image(struct nk_image* image, const char* frame_buffer, const int width, const int height)\n{\n    if (image && frame_buffer && (width > 0) && (height > 0))\n    {\n        const unsigned char* src = (const unsigned char*)frame_buffer;\n        INT row = ((width * 3 + 3) & ~3);\n        LPBYTE lpBuf, pb = NULL;\n        BITMAPINFO bi = { 0 };\n        HBITMAP hbm;\n        int v, i;\n\n        image->w = width;\n        image->h = height;\n        image->region[0] = 0;\n        image->region[1] = 0;\n        image->region[2] = width;\n        image->region[3] = height;\n\n        bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);\n        bi.bmiHeader.biWidth = width;\n        bi.bmiHeader.biHeight = height;\n        bi.bmiHeader.biPlanes = 1;\n        bi.bmiHeader.biBitCount = 24;\n        bi.bmiHeader.biCompression = BI_RGB;\n        bi.bmiHeader.biSizeImage = row * height;\n\n        hbm = CreateDIBSection(NULL, &bi, DIB_RGB_COLORS, (void**)&lpBuf, NULL, 0);\n\n        pb = lpBuf + row * height;\n        for (v = 0; v < height; v++)\n        {\n            pb -= row;\n            for (i = 0; i < row; i += 3)\n            {\n                pb[i + 0] = src[0];\n                pb[i + 1] = src[1];\n                pb[i + 2] = src[2];\n                src += 3;\n            }\n        }\n        SetDIBits(NULL, hbm, 0, height, lpBuf, &bi, DIB_RGB_COLORS);\n        image->handle.ptr = hbm;\n    }\n}\n\nstatic void\nnk_delete_image(struct nk_image* image)\n{\n    if (image && image->handle.id != 0)\n    {\n        HBITMAP hbm = (HBITMAP)image->handle.ptr;\n        DeleteObject(hbm);\n        memset(image, 0, sizeof(struct nk_image));\n    }\n}\n\nstatic void\nnk_gdi_draw_image(nk_gdi_ctx gdi, short x, short y, unsigned short w, unsigned short h,\n    struct nk_image img, struct nk_color col)\n{\n    HBITMAP hbm = (HBITMAP)img.handle.ptr;\n    HDC     hDCBits;\n    BITMAP  bitmap;\n\n    if (!gdi->memory_dc || !hbm)\n        return;\n\n    hDCBits = CreateCompatibleDC(gdi->memory_dc);\n    GetObject(hbm, sizeof(BITMAP), (LPSTR)&bitmap);\n    SelectObject(hDCBits, hbm);\n    StretchBlt(gdi->memory_dc, x, y, w, h, hDCBits, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);\n    DeleteDC(hDCBits);\n}\n\nstatic COLORREF\nconvert_color(struct nk_color c)\n{\n    return c.r | (c.g << 8) | (c.b << 16);\n}\n\nstatic void\nnk_gdi_scissor(HDC dc, float x, float y, float w, float h)\n{\n    SelectClipRgn(dc, NULL);\n    IntersectClipRect(dc, (int)x, (int)y, (int)(x + w + 1), (int)(y + h + 1));\n}\n\nstatic void\nnk_gdi_stroke_line(HDC dc, short x0, short y0, short x1,\n    short y1, unsigned int line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n\n    HPEN pen = NULL;\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    }\n    else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    MoveToEx(dc, x0, y0, NULL);\n    LineTo(dc, x1, y1);\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_stroke_rect(HDC dc, short x, short y, unsigned short w,\n    unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    HGDIOBJ br;\n    HPEN pen = NULL;\n\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    }\n    else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    br = SelectObject(dc, GetStockObject(NULL_BRUSH));\n    if (r == 0) {\n        Rectangle(dc, x, y, x + w, y + h);\n    }\n    else {\n        RoundRect(dc, x, y, x + w, y + h, r, r);\n    }\n    SelectObject(dc, br);\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_fill_rect(HDC dc, short x, short y, unsigned short w,\n    unsigned short h, unsigned short r, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n\n    if (r == 0) {\n        RECT rect;\n        SetRect(&rect, x, y, x + w, y + h);\n        SetBkColor(dc, color);\n        ExtTextOutW(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);\n    }\n    else {\n        SetDCPenColor(dc, color);\n        SetDCBrushColor(dc, color);\n        RoundRect(dc, x, y, x + w, y + h, r, r);\n    }\n}\nstatic void\nnk_gdi_set_vertexColor(PTRIVERTEX tri, struct nk_color col)\n{\n    tri->Red = col.r << 8;\n    tri->Green = col.g << 8;\n    tri->Blue = col.b << 8;\n    tri->Alpha = 0xff << 8;\n}\n\nstatic void\nnk_gdi_rect_multi_color(nk_gdi_ctx gdi, HDC dc, short x, short y, unsigned short w,\n    unsigned short h, struct nk_color left, struct nk_color top,\n    struct nk_color right, struct nk_color bottom)\n{\n    BLENDFUNCTION alphaFunction;\n    // GRADIENT_RECT gRect;\n    GRADIENT_TRIANGLE gTri[2];\n    TRIVERTEX vt[4];\n    alphaFunction.BlendOp = AC_SRC_OVER;\n    alphaFunction.BlendFlags = 0;\n    alphaFunction.SourceConstantAlpha = 0;\n    alphaFunction.AlphaFormat = AC_SRC_ALPHA;\n\n    /* TODO: This Case Needs Repair.*/\n    /* Top Left Corner */\n    vt[0].x = x;\n    vt[0].y = y;\n    nk_gdi_set_vertexColor(&vt[0], left);\n    /* Top Right Corner */\n    vt[1].x = x + w;\n    vt[1].y = y;\n    nk_gdi_set_vertexColor(&vt[1], top);\n    /* Bottom Left Corner */\n    vt[2].x = x;\n    vt[2].y = y + h;\n    nk_gdi_set_vertexColor(&vt[2], right);\n\n    /* Bottom Right Corner */\n    vt[3].x = x + w;\n    vt[3].y = y + h;\n    nk_gdi_set_vertexColor(&vt[3], bottom);\n\n    gTri[0].Vertex1 = 0;\n    gTri[0].Vertex2 = 1;\n    gTri[0].Vertex3 = 2;\n    gTri[1].Vertex1 = 2;\n    gTri[1].Vertex2 = 1;\n    gTri[1].Vertex3 = 3;\n    GdiGradientFill(dc, vt, 4, gTri, 2, GRADIENT_FILL_TRIANGLE);\n    AlphaBlend(gdi->window_dc, x, y, x + w, y + h, gdi->memory_dc, x, y, x + w, y + h, alphaFunction);\n\n}\n\nstatic BOOL\nSetPoint(POINT* p, LONG x, LONG y)\n{\n    if (!p)\n        return FALSE;\n    p->x = x;\n    p->y = y;\n    return TRUE;\n}\n\nstatic void\nnk_gdi_fill_triangle(HDC dc, short x0, short y0, short x1,\n    short y1, short x2, short y2, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    POINT points[3];\n\n    SetPoint(&points[0], x0, y0);\n    SetPoint(&points[1], x1, y1);\n    SetPoint(&points[2], x2, y2);\n\n    SetDCPenColor(dc, color);\n    SetDCBrushColor(dc, color);\n    Polygon(dc, points, 3);\n}\n\nstatic void\nnk_gdi_stroke_triangle(HDC dc, short x0, short y0, short x1,\n    short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    POINT points[4];\n    HPEN pen = NULL;\n\n    SetPoint(&points[0], x0, y0);\n    SetPoint(&points[1], x1, y1);\n    SetPoint(&points[2], x2, y2);\n    SetPoint(&points[3], x0, y0);\n\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    }\n    else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    Polyline(dc, points, 4);\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_fill_polygon(HDC dc, const struct nk_vec2i* pnts, int count, struct nk_color col)\n{\n    int i = 0;\n#define MAX_POINTS 64\n    POINT points[MAX_POINTS];\n    COLORREF color = convert_color(col);\n    SetDCBrushColor(dc, color);\n    SetDCPenColor(dc, color);\n    for (i = 0; i < count && i < MAX_POINTS; ++i) {\n        points[i].x = pnts[i].x;\n        points[i].y = pnts[i].y;\n    }\n    Polygon(dc, points, i);\n#undef MAX_POINTS\n}\n\nstatic void\nnk_gdi_stroke_polygon(HDC dc, const struct nk_vec2i* pnts, int count,\n    unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    HPEN pen = NULL;\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    }\n    else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    if (count > 0) {\n        int i;\n        MoveToEx(dc, pnts[0].x, pnts[0].y, NULL);\n        for (i = 1; i < count; ++i)\n            LineTo(dc, pnts[i].x, pnts[i].y);\n        LineTo(dc, pnts[0].x, pnts[0].y);\n    }\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_stroke_polyline(HDC dc, const struct nk_vec2i* pnts,\n    int count, unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    HPEN pen = NULL;\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    }\n    else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    if (count > 0) {\n        int i;\n        MoveToEx(dc, pnts[0].x, pnts[0].y, NULL);\n        for (i = 1; i < count; ++i)\n            LineTo(dc, pnts[i].x, pnts[i].y);\n    }\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_fill_circle(HDC dc, short x, short y, unsigned short w,\n    unsigned short h, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    SetDCBrushColor(dc, color);\n    SetDCPenColor(dc, color);\n    Ellipse(dc, x, y, x + w, y + h);\n}\n\nstatic void\nnk_gdi_stroke_circle(HDC dc, short x, short y, unsigned short w,\n    unsigned short h, unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    HPEN pen = NULL;\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    }\n    else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    SetDCBrushColor(dc, OPAQUE);\n    Ellipse(dc, x, y, x + w, y + h);\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_stroke_curve(HDC dc, struct nk_vec2i p1,\n    struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,\n    unsigned short line_thickness, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    POINT p[4];\n    HPEN pen = NULL;\n\n    SetPoint(&p[0], p1.x, p1.y);\n    SetPoint(&p[1], p2.x, p2.y);\n    SetPoint(&p[2], p3.x, p3.y);\n    SetPoint(&p[3], p4.x, p4.y);\n\n    if (line_thickness == 1) {\n        SetDCPenColor(dc, color);\n    }\n    else {\n        pen = CreatePen(PS_SOLID, line_thickness, color);\n        SelectObject(dc, pen);\n    }\n\n    SetDCBrushColor(dc, OPAQUE);\n    PolyBezier(dc, p, 4);\n\n    if (pen) {\n        SelectObject(dc, GetStockObject(DC_PEN));\n        DeleteObject(pen);\n    }\n}\n\nstatic void\nnk_gdi_draw_text(HDC dc, short x, short y, unsigned short w, unsigned short h,\n    const char* text, int len, GdiFont* font, struct nk_color cbg, struct nk_color cfg)\n{\n    int wsize;\n    WCHAR* wstr;\n\n    if (!text || !font || !len) return;\n\n    wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);\n    wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));\n    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);\n\n    SetBkColor(dc, convert_color(cbg));\n    SetTextColor(dc, convert_color(cfg));\n\n    SelectObject(dc, font->handle);\n    ExtTextOutW(dc, x, y, ETO_OPAQUE, NULL, wstr, wsize, NULL);\n}\n\nstatic void\nnk_gdi_clear(nk_gdi_ctx gdi, HDC dc, struct nk_color col)\n{\n    COLORREF color = convert_color(col);\n    RECT rect;\n    SetRect(&rect, 0, 0, gdi->width, gdi->height);\n    SetBkColor(dc, color);\n\n    ExtTextOutW(dc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);\n}\n\nstatic void\nnk_gdi_blit(nk_gdi_ctx gdi, HDC dc)\n{\n    BitBlt(dc, 0, 0, gdi->width, gdi->height, gdi->memory_dc, 0, 0, SRCCOPY);\n\n}\n\nGdiFont*\nnk_gdifont_create(const char* name, int size)\n{\n    TEXTMETRICW metric;\n    GdiFont* font = (GdiFont*)calloc(1, sizeof(GdiFont));\n    if (!font)\n        return NULL;\n    font->dc = CreateCompatibleDC(0);\n    font->handle = CreateFontA(size, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, name);\n    SelectObject(font->dc, font->handle);\n    GetTextMetricsW(font->dc, &metric);\n    font->height = metric.tmHeight;\n    return font;\n}\n\nstatic float\nnk_gdifont_get_text_width(nk_handle handle, float height, const char* text, int len)\n{\n    GdiFont* font = (GdiFont*)handle.ptr;\n    SIZE size;\n    int wsize;\n    WCHAR* wstr;\n    if (!font || !text)\n        return 0;\n\n    wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);\n    wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));\n    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);\n    if (GetTextExtentPoint32W(font->dc, wstr, wsize, &size))\n        return (float)size.cx;\n    return -1.0f;\n}\n\nvoid\nnk_gdifont_del(GdiFont* font)\n{\n    if (!font) return;\n    DeleteObject(font->handle);\n    DeleteDC(font->dc);\n    free(font);\n}\n\nstatic void\nnk_gdi_clipboard_paste(nk_handle usr, struct nk_text_edit* edit)\n{\n    (void)usr;\n    if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))\n    {\n        HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);\n        if (mem)\n        {\n            SIZE_T size = GlobalSize(mem) - 1;\n            if (size)\n            {\n                LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);\n                if (wstr)\n                {\n                    int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), NULL, 0, NULL, NULL);\n                    if (utf8size)\n                    {\n                        char* utf8 = (char*)malloc(utf8size);\n                        if (utf8)\n                        {\n                            WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), utf8, utf8size, NULL, NULL);\n                            nk_textedit_paste(edit, utf8, utf8size);\n                            free(utf8);\n                        }\n                    }\n                    GlobalUnlock(mem);\n                }\n            }\n        }\n        CloseClipboard();\n    }\n}\n\nstatic void\nnk_gdi_clipboard_copy(nk_handle usr, const char* text, int len)\n{\n    if (OpenClipboard(NULL))\n    {\n        int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);\n        if (wsize)\n        {\n            HGLOBAL mem = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));\n            if (mem)\n            {\n                wchar_t* wstr = (wchar_t*)GlobalLock(mem);\n                if (wstr)\n                {\n                    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);\n                    wstr[wsize] = 0;\n                    GlobalUnlock(mem);\n\n                    SetClipboardData(CF_UNICODETEXT, mem);\n                }\n            }\n        }\n        CloseClipboard();\n    }\n}\n\nNK_API struct nk_context*\nnk_gdi_init(nk_gdi_ctx* gdi, GdiFont* gdifont, HDC window_dc, unsigned int width, unsigned int height)\n{\n    *gdi = (nk_gdi_ctx)malloc(sizeof(struct _nk_gdi_ctx));\n\n    struct nk_user_font* font = &gdifont->nk;\n    font->userdata = nk_handle_ptr(gdifont);\n    font->height = (float)gdifont->height;\n    font->width = nk_gdifont_get_text_width;\n\n    (*gdi)->bitmap = CreateCompatibleBitmap(window_dc, width, height);\n    (*gdi)->window_dc = window_dc;\n    (*gdi)->memory_dc = CreateCompatibleDC(window_dc);\n    (*gdi)->width = width;\n    (*gdi)->height = height;\n    SelectObject((*gdi)->memory_dc, (*gdi)->bitmap);\n\n    nk_init_default(&(*gdi)->ctx, font);\n    (*gdi)->ctx.clip.copy = nk_gdi_clipboard_copy;\n    (*gdi)->ctx.clip.paste = nk_gdi_clipboard_paste;\n    return &(*gdi)->ctx;\n}\n\nNK_API void\nnk_gdi_set_font(nk_gdi_ctx gdi, GdiFont* gdifont)\n{\n    struct nk_user_font* font = &gdifont->nk;\n    font->userdata = nk_handle_ptr(gdifont);\n    font->height = (float)gdifont->height;\n    font->width = nk_gdifont_get_text_width;\n    nk_style_set_font(&gdi->ctx, font);\n}\n\nNK_API int\nnk_gdi_handle_event(nk_gdi_ctx gdi, HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)\n{\n    static int insert_toggle = 0;\n    switch (msg)\n    {\n    case WM_SIZE:\n    {\n        unsigned width = LOWORD(lparam);\n        unsigned height = HIWORD(lparam);\n        if (width != gdi->width || height != gdi->height)\n        {\n            DeleteObject(gdi->bitmap);\n            gdi->bitmap = CreateCompatibleBitmap(gdi->window_dc, width, height);\n            gdi->width = width;\n            gdi->height = height;\n            SelectObject(gdi->memory_dc, gdi->bitmap);\n        }\n        break;\n    }\n\n    case WM_PAINT:\n    {\n        PAINTSTRUCT paint;\n        HDC dc = BeginPaint(wnd, &paint);\n        nk_gdi_blit(gdi, dc);\n        EndPaint(wnd, &paint);\n        return 1;\n    }\n\n    case WM_KEYDOWN:\n    case WM_KEYUP:\n    case WM_SYSKEYDOWN:\n    case WM_SYSKEYUP:\n    {\n        int down = !((lparam >> 31) & 1);\n        int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);\n\n        switch (wparam)\n        {\n        case VK_SHIFT:\n        case VK_LSHIFT:\n        case VK_RSHIFT:\n            nk_input_key(&gdi->ctx, NK_KEY_SHIFT, down);\n            return 1;\n\n        case VK_DELETE:\n            nk_input_key(&gdi->ctx, NK_KEY_DEL, down);\n            return 1;\n\n        case VK_RETURN:\n        case VK_SEPARATOR:\n            nk_input_key(&gdi->ctx, NK_KEY_ENTER, down);\n            return 1;\n\n        case VK_TAB:\n            nk_input_key(&gdi->ctx, NK_KEY_TAB, down);\n            return 1;\n\n        case VK_LEFT:\n            if (ctrl)\n                nk_input_key(&gdi->ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else\n                nk_input_key(&gdi->ctx, NK_KEY_LEFT, down);\n            return 1;\n\n        case VK_RIGHT:\n            if (ctrl)\n                nk_input_key(&gdi->ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else\n                nk_input_key(&gdi->ctx, NK_KEY_RIGHT, down);\n            return 1;\n\n        case VK_BACK:\n            nk_input_key(&gdi->ctx, NK_KEY_BACKSPACE, down);\n            return 1;\n\n        case VK_HOME:\n            nk_input_key(&gdi->ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(&gdi->ctx, NK_KEY_SCROLL_START, down);\n            return 1;\n\n        case VK_END:\n            nk_input_key(&gdi->ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(&gdi->ctx, NK_KEY_SCROLL_END, down);\n            return 1;\n\n        case VK_NEXT:\n            nk_input_key(&gdi->ctx, NK_KEY_SCROLL_DOWN, down);\n            return 1;\n\n        case VK_PRIOR:\n            nk_input_key(&gdi->ctx, NK_KEY_SCROLL_UP, down);\n            return 1;\n\n        case VK_ESCAPE:\n            nk_input_key(&gdi->ctx, NK_KEY_TEXT_RESET_MODE, down);\n            return 1;\n\n        case VK_INSERT:\n        /* Only switch on release to avoid repeat issues\n         * kind of confusing since we have to negate it but we're already\n         * hacking it since Nuklear treats them as two separate keys rather\n         * than a single toggle state */\n            if (!down) {\n                insert_toggle = !insert_toggle;\n                if (insert_toggle) {\n                    nk_input_key(&gdi->ctx, NK_KEY_TEXT_INSERT_MODE, !down);\n                    /* nk_input_key(&gdi->ctx, NK_KEY_TEXT_REPLACE_MODE, down); */\n                } else {\n                    nk_input_key(&gdi->ctx, NK_KEY_TEXT_REPLACE_MODE, !down);\n                    /* nk_input_key(&gdi->ctx, NK_KEY_TEXT_INSERT_MODE, down); */\n                }\n            }\n            return 1;\n\n        case 'A':\n            if (ctrl) {\n                nk_input_key(&gdi->ctx, NK_KEY_TEXT_SELECT_ALL, down);\n                return 1;\n            }\n            break;\n\n        case 'B':\n            if (ctrl) {\n                nk_input_key(&gdi->ctx, NK_KEY_TEXT_LINE_START, down);\n                return 1;\n            }\n            break;\n\n        case 'E':\n            if (ctrl) {\n                nk_input_key(&gdi->ctx, NK_KEY_TEXT_LINE_END, down);\n                return 1;\n            }\n            break;\n\n        case 'C':\n            if (ctrl) {\n                nk_input_key(&gdi->ctx, NK_KEY_COPY, down);\n                return 1;\n            }\n            break;\n\n        case 'V':\n            if (ctrl) {\n                nk_input_key(&gdi->ctx, NK_KEY_PASTE, down);\n                return 1;\n            }\n            break;\n\n        case 'X':\n            if (ctrl) {\n                nk_input_key(&gdi->ctx, NK_KEY_CUT, down);\n                return 1;\n            }\n            break;\n\n        case 'Z':\n            if (ctrl) {\n                nk_input_key(&gdi->ctx, NK_KEY_TEXT_UNDO, down);\n                return 1;\n            }\n            break;\n\n        case 'R':\n            if (ctrl) {\n                nk_input_key(&gdi->ctx, NK_KEY_TEXT_REDO, down);\n                return 1;\n            }\n            break;\n        }\n        return 0;\n    }\n\n    case WM_CHAR:\n        if (wparam >= 32)\n        {\n            nk_input_unicode(&gdi->ctx, (nk_rune)wparam);\n            return 1;\n        }\n        break;\n\n    case WM_LBUTTONDOWN:\n        nk_input_button(&gdi->ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_LBUTTONUP:\n        nk_input_button(&gdi->ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        nk_input_button(&gdi->ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_RBUTTONDOWN:\n        nk_input_button(&gdi->ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_RBUTTONUP:\n        nk_input_button(&gdi->ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_MBUTTONDOWN:\n        nk_input_button(&gdi->ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_MBUTTONUP:\n        nk_input_button(&gdi->ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_XBUTTONDOWN:\n        switch (GET_XBUTTON_WPARAM(wparam)) {\n        case XBUTTON1:\n            nk_input_button(&gdi->ctx, NK_BUTTON_X1, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n            break;\n        case XBUTTON2:\n            nk_input_button(&gdi->ctx, NK_BUTTON_X2, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n            break;\n        }\n        SetCapture(wnd);\n        return 1;\n\n    case WM_XBUTTONUP:\n        switch (GET_XBUTTON_WPARAM(wparam)) {\n        case XBUTTON1:\n            nk_input_button(&gdi->ctx, NK_BUTTON_X1, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n            break;\n        case XBUTTON2:\n            nk_input_button(&gdi->ctx, NK_BUTTON_X2, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n            break;\n        }\n        ReleaseCapture();\n        return 1;\n\n    case WM_MOUSEWHEEL:\n        nk_input_scroll(&gdi->ctx, nk_vec2(0, (float)(short)HIWORD(wparam) / WHEEL_DELTA));\n        return 1;\n\n    case WM_MOUSEMOVE:\n        nk_input_motion(&gdi->ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));\n        return 1;\n\n    case WM_LBUTTONDBLCLK:\n        nk_input_button(&gdi->ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        return 1;\n    }\n\n    return 0;\n}\n\nNK_API void\nnk_gdi_shutdown(nk_gdi_ctx gdi)\n{\n    DeleteObject(gdi->memory_dc);\n    DeleteObject(gdi->bitmap);\n    nk_free(&gdi->ctx);\n}\n\nNK_API void\nnk_gdi_render(nk_gdi_ctx gdi, struct nk_color clear)\n{\n    const struct nk_command* cmd;\n\n    HDC memory_dc = gdi->memory_dc;\n    SelectObject(memory_dc, GetStockObject(DC_PEN));\n    SelectObject(memory_dc, GetStockObject(DC_BRUSH));\n    nk_gdi_clear(gdi, memory_dc, clear);\n\n    nk_foreach(cmd, &gdi->ctx)\n    {\n        switch (cmd->type) {\n        case NK_COMMAND_NOP: break;\n        case NK_COMMAND_SCISSOR: {\n            const struct nk_command_scissor* s = (const struct nk_command_scissor*)cmd;\n            nk_gdi_scissor(memory_dc, s->x, s->y, s->w, s->h);\n        } break;\n        case NK_COMMAND_LINE: {\n            const struct nk_command_line* l = (const struct nk_command_line*)cmd;\n            nk_gdi_stroke_line(memory_dc, l->begin.x, l->begin.y, l->end.x,\n                l->end.y, l->line_thickness, l->color);\n        } break;\n        case NK_COMMAND_RECT: {\n            const struct nk_command_rect* r = (const struct nk_command_rect*)cmd;\n            nk_gdi_stroke_rect(memory_dc, r->x, r->y, r->w, r->h,\n                (unsigned short)r->rounding, r->line_thickness, r->color);\n        } break;\n        case NK_COMMAND_RECT_FILLED: {\n            const struct nk_command_rect_filled* r = (const struct nk_command_rect_filled*)cmd;\n            nk_gdi_fill_rect(memory_dc, r->x, r->y, r->w, r->h,\n                (unsigned short)r->rounding, r->color);\n        } break;\n        case NK_COMMAND_CIRCLE: {\n            const struct nk_command_circle* c = (const struct nk_command_circle*)cmd;\n            nk_gdi_stroke_circle(memory_dc, c->x, c->y, c->w, c->h, c->line_thickness, c->color);\n        } break;\n        case NK_COMMAND_CIRCLE_FILLED: {\n            const struct nk_command_circle_filled* c = (const struct nk_command_circle_filled*)cmd;\n            nk_gdi_fill_circle(memory_dc, c->x, c->y, c->w, c->h, c->color);\n        } break;\n        case NK_COMMAND_TRIANGLE: {\n            const struct nk_command_triangle* t = (const struct nk_command_triangle*)cmd;\n            nk_gdi_stroke_triangle(memory_dc, t->a.x, t->a.y, t->b.x, t->b.y,\n                t->c.x, t->c.y, t->line_thickness, t->color);\n        } break;\n        case NK_COMMAND_TRIANGLE_FILLED: {\n            const struct nk_command_triangle_filled* t = (const struct nk_command_triangle_filled*)cmd;\n            nk_gdi_fill_triangle(memory_dc, t->a.x, t->a.y, t->b.x, t->b.y,\n                t->c.x, t->c.y, t->color);\n        } break;\n        case NK_COMMAND_POLYGON: {\n            const struct nk_command_polygon* p = (const struct nk_command_polygon*)cmd;\n            nk_gdi_stroke_polygon(memory_dc, p->points, p->point_count, p->line_thickness, p->color);\n        } break;\n        case NK_COMMAND_POLYGON_FILLED: {\n            const struct nk_command_polygon_filled* p = (const struct nk_command_polygon_filled*)cmd;\n            nk_gdi_fill_polygon(memory_dc, p->points, p->point_count, p->color);\n        } break;\n        case NK_COMMAND_POLYLINE: {\n            const struct nk_command_polyline* p = (const struct nk_command_polyline*)cmd;\n            nk_gdi_stroke_polyline(memory_dc, p->points, p->point_count, p->line_thickness, p->color);\n        } break;\n        case NK_COMMAND_TEXT: {\n            const struct nk_command_text* t = (const struct nk_command_text*)cmd;\n            nk_gdi_draw_text(memory_dc, t->x, t->y, t->w, t->h,\n                (const char*)t->string, t->length,\n                (GdiFont*)t->font->userdata.ptr,\n                t->background, t->foreground);\n        } break;\n        case NK_COMMAND_CURVE: {\n            const struct nk_command_curve* q = (const struct nk_command_curve*)cmd;\n            nk_gdi_stroke_curve(memory_dc, q->begin, q->ctrl[0], q->ctrl[1],\n                q->end, q->line_thickness, q->color);\n        } break;\n        case NK_COMMAND_RECT_MULTI_COLOR: {\n            const struct nk_command_rect_multi_color* r = (const struct nk_command_rect_multi_color*)cmd;\n            nk_gdi_rect_multi_color(gdi, memory_dc, r->x, r->y, r->w, r->h, r->left, r->top, r->right, r->bottom);\n        } break;\n        case NK_COMMAND_IMAGE: {\n            const struct nk_command_image* i = (const struct nk_command_image*)cmd;\n            nk_gdi_draw_image(gdi, i->x, i->y, i->w, i->h, i->img, i->col);\n        } break;\n        case NK_COMMAND_ARC:\n        case NK_COMMAND_ARC_FILLED:\n        default: break;\n        }\n    }\n    nk_gdi_blit(gdi, gdi->window_dc);\n    nk_clear(&gdi->ctx);\n}\n\n#endif\n"
  },
  {
    "path": "demo/gdi_native_nuklear/window.h",
    "content": "#ifndef NK_GDI_WINDOW\n#define NK_GDI_WINDOW\n\n#define NK_GDI_WINDOW_CLS L\"WNDCLS_NkGdi\"\n\n#include <windows.h>\n\n/* Functin pointer types for window callbacks */\ntypedef int(*nkgdi_window_func_close)(void);\ntypedef int(*nkgdi_window_func_draw)(struct nk_context*);\n\n/* Window container / context */\nstruct nkgdi_window\n{\n    /* The window can be sized */\n    int allow_sizing;\n    /* The window can be maximized by double clicking the titlebar */\n    int allow_maximize;\n    /* The window is allowed to be moved by the user */\n    int allow_move;\n    /* The window will render it's title bar */\n    int has_titlebar;\n\n    /* Callbacks */\n    /* Called when the user or os requests a window close (return 1 to accept the reqest)*/\n    nkgdi_window_func_close cb_on_close;\n    /* Called each time the window content should be drawn. Here you will do your nuklear drawing code\n     * but WITHOUT nk_begin and nk_end. Return 1 to keep the window open.\n     */\n    nkgdi_window_func_draw cb_on_draw;\n\n    /* Internal Data */\n    struct\n    {\n        /* Window handle */\n        HWND window_handle;\n\n        /* Nuklear & GDI context */\n        nk_gdi_ctx nk_gdi_ctx;\n        struct nk_context* nk_ctx;\n\n        /* GDI required objects */\n        GdiFont* gdi_font;\n        HDC window_dc;\n\n        /* Internally used state variables */\n        int is_open;\n        int is_draggin;\n        int ws_override;\n        int is_maximized;\n        POINT drag_offset;\n        int width;\n        int height;\n    }_internal;\n};\n\n/* API */\n/* This function will init all resources used by the implementation */\nvoid nkgdi_window_init(void);\n/* This function will free all globally used resources */\nvoid nkgdi_window_shutdown(void);\n/* Creates a new window (for the wnd context) */\nvoid nkgdi_window_create(struct nkgdi_window* wnd, unsigned int width, unsigned int height, const char* name, int posX, int posY);\n/* Updates the window (Windows message loop, nuklear loop and drawing). Returns one as long as the window is valid and open */\nint nkgdi_window_update(struct nkgdi_window* wnd);\n/* Destroys the window context wnd */\nvoid nkgdi_window_destroy(struct nkgdi_window* wnd);\n\n#ifdef NKGDI_IMPLEMENT_WINDOW\n\n/* Predeclare the windows window message procs */\n/* This proc will setup the pointer to the window context */\nLRESULT CALLBACK nkgdi_window_proc_setup(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);\n/* This proc will take the window context pointer and performs operations on it*/\nLRESULT CALLBACK nkgdi_window_proc_run(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam);\n\nvoid nkgdi_window_init(void)\n{\n    /* Describe the window class */\n    WNDCLASSEXW cls;\n    cls.cbSize = sizeof(WNDCLASSEXW);\n    cls.style = CS_OWNDC | CS_DBLCLKS;\n    cls.lpfnWndProc = &nkgdi_window_proc_setup;\n    cls.cbClsExtra = 0;\n    cls.cbWndExtra = 0;\n    cls.hInstance = GetModuleHandle(NULL);\n    cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);\n    cls.hCursor = LoadCursor(NULL, IDC_ARROW);\n    cls.hbrBackground = NULL;\n    cls.lpszMenuName = NULL;\n    cls.lpszClassName = NK_GDI_WINDOW_CLS;\n    cls.hIconSm = NULL;\n\n    /* Register the window class */\n    RegisterClassExW(&cls);\n}\n\nvoid nkgdi_window_shutdown(void)\n{\n    /* Windows class no longer required, unregister it */\n    UnregisterClassW(NK_GDI_WINDOW_CLS, GetModuleHandle(NULL));\n}\n\nvoid nkgdi_window_create(struct nkgdi_window* wnd, unsigned int width, unsigned int height, const char* name, int posX, int posY)\n{\n    DWORD styleEx = WS_EX_WINDOWEDGE;\n    DWORD style = WS_POPUP;\n\n    /* Adjust window size to fit selected window styles */\n    RECT cr;\n    cr.left = 0;\n    cr.top = 0;\n    cr.right = width;\n    cr.bottom = height;\n    AdjustWindowRectEx(&cr, style, FALSE, styleEx);\n\n    /* Create the new window */\n    wnd->_internal.window_handle = CreateWindowExW(\n        styleEx,\n        NK_GDI_WINDOW_CLS,\n        L\"NkGdi\",\n        style | WS_VISIBLE,\n        posX, posY,\n        cr.right - cr.left, cr.bottom - cr.top,\n        NULL, NULL,\n        GetModuleHandleW(NULL),\n        wnd\n    );\n\n    /* Give the window the ascii char name */\n    SetWindowTextA(wnd->_internal.window_handle, name);\n\n    /* Extract the window dc for gdi drawing */\n    wnd->_internal.window_dc = GetWindowDC(wnd->_internal.window_handle);\n\n    /* Create the gdi font required to draw text */\n    wnd->_internal.gdi_font = nk_gdifont_create(\"Arial\", 16);\n\n    /* Init the gdi backend */\n    wnd->_internal.nk_ctx = nk_gdi_init(&wnd->_internal.nk_gdi_ctx, wnd->_internal.gdi_font, wnd->_internal.window_dc, width, height);\n\n    /* Bring all internal variables to a defined and valid initial state */\n    wnd->_internal.is_open = 1;\n    wnd->_internal.is_draggin = 0;\n    wnd->_internal.ws_override = 0;\n    wnd->_internal.is_maximized = 0;\n    wnd->_internal.drag_offset.x = 0;\n    wnd->_internal.drag_offset.y = 0;\n    wnd->_internal.width = width;\n    wnd->_internal.height = height;\n}\n\nvoid nkgdi_window_destroy(struct nkgdi_window* wnd)\n{\n    /* Destroy all objects in reverse order */\n    if (wnd->_internal.nk_gdi_ctx)\n    {\n        nk_gdi_shutdown(wnd->_internal.nk_gdi_ctx);\n    }\n    if (wnd->_internal.gdi_font)\n    {\n        nk_gdifont_del(wnd->_internal.gdi_font);\n    }\n    if (wnd->_internal.window_dc)\n    {\n        ReleaseDC(wnd->_internal.window_handle, wnd->_internal.window_dc);\n    }\n    if (wnd->_internal.window_handle)\n    {\n        CloseWindow(wnd->_internal.window_handle);\n        DestroyWindow(wnd->_internal.window_handle);\n    }\n}\n\nint nkgdi_window_update(struct nkgdi_window* wnd)\n{\n    /* The window will only be updated when it is open / valid */\n    if (wnd->_internal.is_open)\n    {\n        /* First all pending window events will be processed */\n        MSG msg;\n        nk_input_begin(wnd->_internal.nk_ctx);\n        while (PeekMessage(&msg, wnd->_internal.window_handle, 0, 0, PM_REMOVE))\n        {\n            TranslateMessage(&msg);\n            DispatchMessageW(&msg);\n        }\n        nk_input_end(wnd->_internal.nk_ctx);\n\n        /* To setup the nuklear window we need the windows title */\n        char title[1024];\n        GetWindowTextA(wnd->_internal.window_handle, title, 1024);\n\n        /* The nk window flags are beeing create based on the context setup */\n        nk_flags window_flags = NK_WINDOW_BORDER;\n        if(wnd->has_titlebar)\n            window_flags |= NK_WINDOW_CLOSABLE | NK_WINDOW_TITLE;\n        if(!wnd->_internal.is_maximized && wnd->allow_sizing)\n            window_flags |= NK_WINDOW_SCALABLE;\n\n        /* Override the nuklear windows size when required */\n        if (wnd->_internal.ws_override)\n            nk_window_set_bounds(wnd->_internal.nk_ctx, title, nk_rect(0, 0, wnd->_internal.width, wnd->_internal.height));\n\n        /* Start the nuklear window */\n        if (nk_begin(wnd->_internal.nk_ctx, title, nk_rect(0, 0, wnd->_internal.width, wnd->_internal.height), window_flags))\n        {\n            /* Call user drawing callback */\n            if(wnd->cb_on_draw && !wnd->cb_on_draw(wnd->_internal.nk_ctx))\n                wnd->_internal.is_open = 0;\n\n            /* Update the windows window to reflect the nuklear windows size */\n            struct nk_rect bounds = nk_window_get_bounds(wnd->_internal.nk_ctx);\n            if(bounds.w != wnd->_internal.width || bounds.h != wnd->_internal.height)\n                SetWindowPos(wnd->_internal.window_handle, NULL, 0, 0, bounds.w, bounds.h, SWP_NOMOVE | SWP_NOOWNERZORDER);\n        }\n        else\n        {\n            /* Nuklear window was closed. Handle close internally */\n            if(!wnd->cb_on_close || wnd->cb_on_close())\n                wnd->_internal.is_open = 0;\n        }\n        nk_end(wnd->_internal.nk_ctx);\n\n        /* We no longer need the window size override flag to be set */\n        wnd->_internal.ws_override = 0;\n\n        /* Pass context to the nuklear gdi renderer */\n        nk_gdi_render(wnd->_internal.nk_gdi_ctx, nk_rgb(0, 0, 0));\n    }\n\n    return wnd->_internal.is_open;\n}\n\nLRESULT CALLBACK nkgdi_window_proc_setup(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)\n{\n    /* Waiting to receive the NCCREATE message with the custom window data */\n    if (msg == WM_NCCREATE)\n    {\n        /* Extracting the window context from message parameters */\n        CREATESTRUCT* ptrCr = (CREATESTRUCT*)lParam;\n        struct nkgdi_window* nkgdi_wnd = (struct nkgdi_window*)ptrCr->lpCreateParams;\n\n        /* Store the context in the window and redirect any further message to the run window proc*/\n        SetWindowLongPtr(wnd, GWLP_USERDATA, (LONG_PTR)nkgdi_wnd);\n        SetWindowLongPtr(wnd, GWLP_WNDPROC, (LONG_PTR)&nkgdi_window_proc_run);\n\n        /* Already call the run proc so that it gets the chance to handle NCCREATE as well */\n        return nkgdi_window_proc_run(wnd, msg, wParam, lParam);\n    }\n\n    /* Until we get WM_NCCREATE windows is going to handle the messages */\n    return DefWindowProc(wnd, msg, wParam, lParam);\n}\n\nLRESULT CALLBACK nkgdi_window_proc_run(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)\n{\n    /* The window context is extracted from the window data */\n    struct nkgdi_window* nkwnd = (struct nkgdi_window*)GetWindowLongPtrW(wnd, GWLP_USERDATA);\n\n    /* Switch on the message code to handle all required messages */\n    switch (msg)\n    {\n        /* Window close event */\n        case WM_CLOSE:\n            /* Call custom close callback */\n            if(!nkwnd->cb_on_close || nkwnd->cb_on_close())\n                nkwnd->_internal.is_open = 0;\n            return 0; /* No default behaviour. We do it our own way */\n\n        /* Window sizing event (is currently beeing sized) */\n        case WM_SIZING:\n            {\n            /* Size of the client / active are is extracted and stored */\n            RECT cr;\n            GetClientRect(wnd, &cr);\n            nkwnd->_internal.width = cr.right - cr.left;\n            nkwnd->_internal.height = cr.bottom - cr.top;\n            }\n            break;\n\n        /* Window size event (done sizing, maximize, minimize, ...) */\n        case WM_SIZE:\n            {\n            /* Window was maximized */\n            if (wParam == SIZE_MAXIMIZED)\n            {\n                /* Get the nearest monitor and retrive its details */\n                HMONITOR monitor = MonitorFromWindow(wnd, MONITOR_DEFAULTTOPRIMARY);\n                MONITORINFO monitorInfo;\n                monitorInfo.cbSize = sizeof(MONITORINFO);\n                if (GetMonitorInfoW(monitor, &monitorInfo))\n                {\n                    /* Adjust the window size and position by the monitor working area (without taskbar) */\n                    nkwnd->_internal.height = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;\n                    nkwnd->_internal.width = monitorInfo.rcWork.right - monitorInfo.rcWork.left;\n                    nkwnd->_internal.ws_override = 1; /* Sizing was done without nuklear beeing aware. So we need to override it */\n                    nkwnd->_internal.is_maximized = 1;\n                    SetWindowPos(wnd, NULL, 0, 0, nkwnd->_internal.width, nkwnd->_internal.height, SWP_NOMOVE | SWP_NOZORDER);\n                }\n            }\n            /* Window was restored (no longer maximized) */\n            else if (wParam == SIZE_RESTORED)\n            {\n                nkwnd->_internal.is_maximized = 0;\n            }\n\n            /* Always get the new bounds of the window */\n            RECT cr;\n            GetClientRect(wnd, &cr);\n            nkwnd->_internal.width = cr.right - cr.left;\n            nkwnd->_internal.height = cr.bottom - cr.top;\n            }\n            break;\n\n        /* Mouse started left click */\n        case WM_LBUTTONDOWN:\n            {\n            /* Handle dragging when allowed, has titlebar and mouse is in titlebar (Y <= 30) */\n            if (HIWORD(lParam) <= 30 && nkwnd->allow_move && nkwnd->has_titlebar)\n            {\n                /* Mark dragging internally and store mouse click offset */\n                nkwnd->_internal.is_draggin = 1;\n                nkwnd->_internal.drag_offset.x = LOWORD(lParam);\n                nkwnd->_internal.drag_offset.y = HIWORD(lParam);\n            }\n            }\n            break;\n\n        /* Mouse stoped left click */\n        case WM_LBUTTONUP:\n            /* No longer dragging the window */\n            nkwnd->_internal.is_draggin = 0;\n            break;\n\n        /* Mouse is moving on the window */\n        case WM_MOUSEMOVE:\n            {\n            /* When we are dragging and are not maximized process dragging */\n            if (nkwnd->_internal.is_draggin && !nkwnd->_internal.is_maximized)\n            {\n                /* Get the current global position of the mouse */\n                POINT cursorPos;\n                GetCursorPos(&cursorPos);\n                /* Substract the internal offset */\n                cursorPos.x -= nkwnd->_internal.drag_offset.x;\n                cursorPos.y -= nkwnd->_internal.drag_offset.y;\n                /* Update position of out window and make sure window is in a movable state (= Restored) */\n                ShowWindow(wnd, SW_RESTORE);\n                SetWindowPos(wnd, NULL, cursorPos.x, cursorPos.y, 0, 0, SWP_NOSIZE | SWP_NOZORDER);\n            }\n            }\n            break;\n\n        /* Mouse double clicked */\n        case WM_LBUTTONDBLCLK:\n            {\n            /* Will only affect window when on the titlebar */\n            if (HIWORD(lParam) <= 30 && nkwnd->allow_maximize && nkwnd->has_titlebar)\n            {\n                /* When the window is already maximized restore it */\n                if (nkwnd->_internal.is_maximized)\n                {\n                    ShowWindow(wnd, SW_RESTORE);\n                }\n                /* Else we gonna do maximize it*/\n                else\n                {\n                    ShowWindow(wnd, SW_MAXIMIZE);\n                }\n                /* We overrideed the window size, make sure to affect the nk window as well */\n                nkwnd->_internal.ws_override = 1;\n            }\n            }\n            break;\n    }\n\n    /* Allow nuklear to handle the message as well */\n    if (nkwnd->_internal.nk_gdi_ctx && nk_gdi_handle_event(nkwnd->_internal.nk_gdi_ctx, wnd, msg, wParam, lParam))\n        return 0;\n\n    /* In case we reach this line our code and nuklear did not respond to the message. Allow windows to handle it s*/\n    return DefWindowProc(wnd, msg, wParam, lParam);\n}\n\n#endif\n#endif\n"
  },
  {
    "path": "demo/gdip/build.bat",
    "content": "@echo off\n\ncall \"C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat\" x86\n\ncl /nologo /W3 /O2 /fp:fast /Gm- /Fedemo.exe /D_CRT_SECURE_NO_DEPRECATE main.c user32.lib gdiplus.lib shlwapi.lib /link /incremental:no\n"
  },
  {
    "path": "demo/gdip/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <stdio.h>\n#include <string.h>\n#include <limits.h>\n#include <time.h>\n\n#define WINDOW_WIDTH 800\n#define WINDOW_HEIGHT 600\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_IMPLEMENTATION\n#define NK_GDIP_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_gdip.h\"\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nstatic LRESULT CALLBACK\nWindowProc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)\n{\n    switch (msg) {\n    case WM_DESTROY:\n        PostQuitMessage(0);\n        return 0;\n    }\n    if (nk_gdip_handle_event(wnd, msg, wparam, lparam))\n        return 0;\n    return DefWindowProcW(wnd, msg, wparam, lparam);\n}\n\nint main(void)\n{\n    GdipFont* font;\n    struct nk_context *ctx;\n\n    WNDCLASSW wc;\n    RECT rect = { 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT };\n    DWORD style = WS_OVERLAPPEDWINDOW;\n    DWORD exstyle = WS_EX_APPWINDOW;\n    HWND wnd;\n    int running = 1;\n    int needs_refresh = 1;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    /* Win32 */\n    memset(&wc, 0, sizeof(wc));\n    wc.style = CS_DBLCLKS;\n    wc.lpfnWndProc = WindowProc;\n    wc.hInstance = GetModuleHandleW(0);\n    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);\n    wc.hCursor = LoadCursor(NULL, IDC_ARROW);\n    wc.lpszClassName = L\"NuklearWindowClass\";\n    RegisterClassW(&wc);\n\n    AdjustWindowRectEx(&rect, style, FALSE, exstyle);\n\n    wnd = CreateWindowExW(exstyle, wc.lpszClassName, L\"Nuklear GDI+ Demo\",\n        style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT,\n        rect.right - rect.left, rect.bottom - rect.top,\n        NULL, NULL, wc.hInstance, NULL);\n\n    /* GUI */\n    ctx = nk_gdip_init(wnd, WINDOW_WIDTH, WINDOW_HEIGHT);\n    font = nk_gdipfont_create(\"Arial\", 12);\n    nk_gdip_set_font(font);\n\n    while (running)\n    {\n        /* Input */\n        MSG msg;\n        nk_input_begin(ctx);\n        if (needs_refresh == 0) {\n            if (GetMessageW(&msg, NULL, 0, 0) <= 0)\n                running = 0;\n            else {\n                TranslateMessage(&msg);\n                DispatchMessageW(&msg);\n            }\n            needs_refresh = 1;\n        } else needs_refresh = 0;\n        while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {\n            if (msg.message == WM_QUIT)\n                running = 0;\n            TranslateMessage(&msg);\n            DispatchMessageW(&msg);\n            needs_refresh = 1;\n        }\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 200, 200),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 22, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        nk_gdip_render(NK_ANTI_ALIASING_ON, nk_rgb(30,30,30));\n    }\n\n    nk_gdipfont_del(font);\n    nk_gdip_shutdown();\n    UnregisterClassW(wc.lpszClassName, wc.hInstance);\n    return 0;\n}\n"
  },
  {
    "path": "demo/gdip/nuklear_gdip.h",
    "content": "/*\n * Nuklear - 1.40.8 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2017 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_GDIP_H_\n#define NK_GDIP_H_\n\n#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <shlwapi.h>\n\n/* font */\ntypedef struct GdipFont GdipFont;\nNK_API GdipFont* nk_gdipfont_create(const char *name, int size);\nNK_API GdipFont* nk_gdipfont_create_from_file(const WCHAR* filename, int size);\nNK_API GdipFont* nk_gdipfont_create_from_memory(const void* membuf, int membufSize, int size);\nNK_API void nk_gdipfont_del(GdipFont *font);\n\nNK_API struct nk_context* nk_gdip_init(HWND hwnd, unsigned int width, unsigned int height);\nNK_API void nk_gdip_set_font(GdipFont *font);\nNK_API int nk_gdip_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);\nNK_API void nk_gdip_render(enum nk_anti_aliasing AA, struct nk_color clear);\nNK_API void nk_gdip_shutdown(void);\n\n/* image */\nNK_API struct nk_image nk_gdip_load_image_from_file(const WCHAR* filename);\nNK_API struct nk_image nk_gdip_load_image_from_memory(const void* membuf, nk_uint membufSize);\nNK_API void nk_gdip_image_free(struct nk_image image);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_GDIP_IMPLEMENTATION\n\n#include <stdlib.h>\n#include <malloc.h>\n#define _USE_MATH_DEFINES\n#include <math.h>\n\n/* manually declare everything GDI+ needs, because\n   GDI+ headers are not usable from C */\n#define WINGDIPAPI __stdcall\n#define GDIPCONST const\n\ntypedef struct GpGraphics GpGraphics;\ntypedef struct GpImage GpImage;\ntypedef struct GpPen GpPen;\ntypedef struct GpBrush GpBrush;\ntypedef struct GpStringFormat GpStringFormat;\ntypedef struct GpFont GpFont;\ntypedef struct GpFontFamily GpFontFamily;\ntypedef struct GpFontCollection GpFontCollection;\n\ntypedef GpImage GpBitmap;\ntypedef GpBrush GpSolidFill;\n\ntypedef int Status;\ntypedef Status GpStatus;\n\ntypedef float REAL;\ntypedef DWORD ARGB;\ntypedef POINT GpPoint;\n\ntypedef enum {\n    TextRenderingHintSystemDefault = 0,\n    TextRenderingHintSingleBitPerPixelGridFit = 1,\n    TextRenderingHintSingleBitPerPixel = 2,\n    TextRenderingHintAntiAliasGridFit = 3,\n    TextRenderingHintAntiAlias = 4,\n    TextRenderingHintClearTypeGridFit = 5\n} TextRenderingHint;\n\ntypedef enum {\n    StringFormatFlagsDirectionRightToLeft    = 0x00000001,\n    StringFormatFlagsDirectionVertical       = 0x00000002,\n    StringFormatFlagsNoFitBlackBox           = 0x00000004,\n    StringFormatFlagsDisplayFormatControl    = 0x00000020,\n    StringFormatFlagsNoFontFallback          = 0x00000400,\n    StringFormatFlagsMeasureTrailingSpaces   = 0x00000800,\n    StringFormatFlagsNoWrap                  = 0x00001000,\n    StringFormatFlagsLineLimit               = 0x00002000,\n    StringFormatFlagsNoClip                  = 0x00004000\n} StringFormatFlags;\n\ntypedef enum\n{\n    QualityModeInvalid   = -1,\n    QualityModeDefault   = 0,\n    QualityModeLow       = 1,\n    QualityModeHigh      = 2\n} QualityMode;\n\ntypedef enum\n{\n    SmoothingModeInvalid     = QualityModeInvalid,\n    SmoothingModeDefault     = QualityModeDefault,\n    SmoothingModeHighSpeed   = QualityModeLow,\n    SmoothingModeHighQuality = QualityModeHigh,\n    SmoothingModeNone,\n    SmoothingModeAntiAlias,\n    SmoothingModeAntiAlias8x4 = SmoothingModeAntiAlias,\n    SmoothingModeAntiAlias8x8\n} SmoothingMode;\n\ntypedef enum\n{\n    FontStyleRegular    = 0,\n    FontStyleBold       = 1,\n    FontStyleItalic     = 2,\n    FontStyleBoldItalic = 3,\n    FontStyleUnderline  = 4,\n    FontStyleStrikeout  = 8\n} FontStyle;\n\ntypedef enum {\n    FillModeAlternate,\n    FillModeWinding\n} FillMode;\n\ntypedef enum {\n    CombineModeReplace,\n    CombineModeIntersect,\n    CombineModeUnion,\n    CombineModeXor,\n    CombineModeExclude,\n    CombineModeComplement\n} CombineMode;\n\ntypedef enum {\n    UnitWorld,\n    UnitDisplay,\n    UnitPixel,\n    UnitPoint,\n    UnitInch,\n    UnitDocument,\n    UnitMillimeter\n} Unit;\n\ntypedef struct {\n    FLOAT X;\n    FLOAT Y;\n    FLOAT Width;\n    FLOAT Height;\n} RectF;\n\ntypedef enum {\n    DebugEventLevelFatal,\n    DebugEventLevelWarning\n} DebugEventLevel;\n\ntypedef VOID (WINAPI *DebugEventProc)(DebugEventLevel level, CHAR *message);\n\ntypedef struct {\n    UINT32 GdiplusVersion;\n    DebugEventProc DebugEventCallback;\n    BOOL SuppressBackgroundThread;\n    BOOL SuppressExternalCodecs;\n} GdiplusStartupInput;\n\ntypedef Status (WINAPI *NotificationHookProc)(OUT ULONG_PTR *token);\ntypedef VOID (WINAPI *NotificationUnhookProc)(ULONG_PTR token);\n\ntypedef struct {\n    NotificationHookProc NotificationHook;\n    NotificationUnhookProc NotificationUnhook;\n} GdiplusStartupOutput;\n\n/* startup & shutdown */\n\nStatus WINAPI GdiplusStartup(\n    OUT ULONG_PTR *token,\n    const GdiplusStartupInput *input,\n    OUT GdiplusStartupOutput *output);\n\nVOID WINAPI GdiplusShutdown(ULONG_PTR token);\n\n/* image */\n\nGpStatus WINGDIPAPI\nGdipCreateBitmapFromGraphics(INT width,\n                             INT height,\n                             GpGraphics* target,\n                             GpBitmap** bitmap);\n\nGpStatus WINGDIPAPI\nGdipDisposeImage(GpImage *image);\n\nGpStatus WINGDIPAPI\nGdipGetImageGraphicsContext(GpImage *image, GpGraphics **graphics);\n\nGpStatus WINGDIPAPI\nGdipGetImageWidth(GpImage *image, UINT *width);\n\nGpStatus WINGDIPAPI\nGdipGetImageHeight(GpImage *image, UINT *height);\n\nGpStatus WINGDIPAPI\nGdipLoadImageFromFile(GDIPCONST WCHAR* filename, GpImage **image);\n\nGpStatus WINGDIPAPI\nGdipLoadImageFromStream(IStream* stream, GpImage **image);\n\n/* pen */\n\nGpStatus WINGDIPAPI\nGdipCreatePen1(ARGB color, REAL width, Unit unit, GpPen **pen);\n\nGpStatus WINGDIPAPI\nGdipDeletePen(GpPen *pen);\n\nGpStatus WINGDIPAPI\nGdipSetPenWidth(GpPen *pen, REAL width);\n\nGpStatus WINGDIPAPI\nGdipSetPenColor(GpPen *pen, ARGB argb);\n\n/* brush */\n\nGpStatus WINGDIPAPI\nGdipCreateSolidFill(ARGB color, GpSolidFill **brush);\n\nGpStatus WINGDIPAPI\nGdipDeleteBrush(GpBrush *brush);\n\nGpStatus WINGDIPAPI\nGdipSetSolidFillColor(GpSolidFill *brush, ARGB color);\n\n/* font */\n\nGpStatus WINGDIPAPI\nGdipCreateFont(\n    GDIPCONST GpFontFamily  *fontFamily,\n    REAL                 emSize,\n    INT                  style,\n    Unit                 unit,\n    GpFont             **font\n);\n\nGpStatus WINGDIPAPI\nGdipDeleteFont(GpFont* font);\n\nGpStatus WINGDIPAPI\nGdipGetFontSize(GpFont *font, REAL *size);\n\nGpStatus WINGDIPAPI\nGdipCreateFontFamilyFromName(GDIPCONST WCHAR *name,\n                             GpFontCollection *fontCollection,\n                             GpFontFamily **fontFamily);\n\nGpStatus WINGDIPAPI\nGdipDeleteFontFamily(GpFontFamily *fontFamily);\n\nGpStatus WINGDIPAPI\nGdipStringFormatGetGenericTypographic(GpStringFormat **format);\n\nGpStatus WINGDIPAPI\nGdipSetStringFormatFlags(GpStringFormat *format, INT flags);\n\nGpStatus WINGDIPAPI\nGdipDeleteStringFormat(GpStringFormat *format);\n\nGpStatus WINGDIPAPI\nGdipPrivateAddMemoryFont(GpFontCollection* fontCollection,\n                         GDIPCONST void* memory, INT length);\n\nGpStatus WINGDIPAPI\nGdipPrivateAddFontFile(GpFontCollection* fontCollection,\n                       GDIPCONST WCHAR* filename);\n\nGpStatus WINGDIPAPI\nGdipNewPrivateFontCollection(GpFontCollection** fontCollection);\n\nGpStatus WINGDIPAPI\nGdipDeletePrivateFontCollection(GpFontCollection** fontCollection);\n\nGpStatus WINGDIPAPI\nGdipGetFontCollectionFamilyList(GpFontCollection* fontCollection,\n                        INT numSought, GpFontFamily* gpfamilies[], INT* numFound);\n\nGpStatus WINGDIPAPI\nGdipGetFontCollectionFamilyCount(GpFontCollection* fontCollection, INT* numFound);\n\n\n/* graphics */\n\n\nGpStatus WINGDIPAPI\nGdipCreateFromHWND(HWND hwnd, GpGraphics **graphics);\n\nGpStatus WINGDIPAPI\nGdipCreateFromHDC(HDC hdc, GpGraphics **graphics);\n\nGpStatus WINGDIPAPI\nGdipDeleteGraphics(GpGraphics *graphics);\n\nGpStatus WINGDIPAPI\nGdipSetSmoothingMode(GpGraphics *graphics, SmoothingMode smoothingMode);\n\nGpStatus WINGDIPAPI\nGdipSetClipRectI(GpGraphics *graphics, INT x, INT y,\n    INT width, INT height, CombineMode combineMode);\n\nGpStatus WINGDIPAPI\nGdipDrawLineI(GpGraphics *graphics, GpPen *pen, INT x1, INT y1,\n                      INT x2, INT y2);\n\nGpStatus WINGDIPAPI\nGdipDrawArcI(GpGraphics *graphics, GpPen *pen, INT x, INT y,\n    INT width, INT height, REAL startAngle, REAL sweepAngle);\n\nGpStatus WINGDIPAPI\nGdipDrawPieI(GpGraphics *graphics, GpPen *pen, INT x, INT y,\n             INT width, INT height, REAL startAngle, REAL sweepAngle);\n\nGpStatus WINGDIPAPI\nGdipFillPieI(GpGraphics *graphics, GpBrush *brush, INT x, INT y,\n    INT width, INT height, REAL startAngle, REAL sweepAngle);\n\nGpStatus WINGDIPAPI\nGdipDrawRectangleI(GpGraphics *graphics, GpPen *pen, INT x, INT y,\n                   INT width, INT height);\n\nGpStatus WINGDIPAPI\nGdipFillRectangleI(GpGraphics *graphics, GpBrush *brush, INT x, INT y,\n                   INT width, INT height);\n\nGpStatus WINGDIPAPI\nGdipFillPolygonI(GpGraphics *graphics, GpBrush *brush,\n                 GDIPCONST GpPoint *points, INT count, FillMode fillMode);\n\nGpStatus WINGDIPAPI\nGdipDrawPolygonI(GpGraphics *graphics, GpPen *pen, GDIPCONST GpPoint *points,\n                         INT count);\n\nGpStatus WINGDIPAPI\nGdipFillEllipseI(GpGraphics *graphics, GpBrush *brush, INT x, INT y,\n                 INT width, INT height);\n\nGpStatus WINGDIPAPI\nGdipDrawEllipseI(GpGraphics *graphics, GpPen *pen, INT x, INT y,\n                         INT width, INT height);\n\nGpStatus WINGDIPAPI\nGdipDrawBezierI(GpGraphics *graphics, GpPen *pen, INT x1, INT y1,\n                        INT x2, INT y2, INT x3, INT y3, INT x4, INT y4);\n\nGpStatus WINGDIPAPI\nGdipDrawString(\n    GpGraphics               *graphics,\n    GDIPCONST WCHAR          *string,\n    INT                       length,\n    GDIPCONST GpFont         *font,\n    GDIPCONST RectF          *layoutRect,\n    GDIPCONST GpStringFormat *stringFormat,\n    GDIPCONST GpBrush        *brush\n);\n\nGpStatus WINGDIPAPI\nGdipGraphicsClear(GpGraphics *graphics, ARGB color);\n\nGpStatus WINGDIPAPI\nGdipDrawImageI(GpGraphics *graphics, GpImage *image, INT x, INT y);\n\nGpStatus WINGDIPAPI\nGdipDrawImageRectI(GpGraphics *graphics, GpImage *image, INT x, INT y,\n                   INT width, INT height);\n\nGpStatus WINGDIPAPI\nGdipMeasureString(\n    GpGraphics               *graphics,\n    GDIPCONST WCHAR          *string,\n    INT                       length,\n    GDIPCONST GpFont         *font,\n    GDIPCONST RectF          *layoutRect,\n    GDIPCONST GpStringFormat *stringFormat,\n    RectF                    *boundingBox,\n    INT                      *codepointsFitted,\n    INT                      *linesFilled\n);\n\nGpStatus WINGDIPAPI\nGdipSetTextRenderingHint(GpGraphics *graphics, TextRenderingHint mode);\n\nLWSTDAPI_(IStream *) SHCreateMemStream(const BYTE *pInit, _In_ UINT cbInit);\n\nstruct GdipFont\n{\n    struct nk_user_font nk;\n    GpFont* handle;\n};\n\nstatic struct {\n    ULONG_PTR token;\n\n    GpGraphics *window;\n    GpGraphics *memory;\n    GpImage *bitmap;\n    GpPen *pen;\n    GpSolidFill *brush;\n    GpStringFormat *format;\n    GpFontCollection *fontCollection[10];\n    INT curFontCollection;\n\n    struct nk_context ctx;\n} gdip;\n\nstatic ARGB convert_color(struct nk_color c)\n{\n    return (c.a << 24) | (c.r << 16) | (c.g << 8) | c.b;\n}\n\nstatic void\nnk_gdip_scissor(float x, float y, float w, float h)\n{\n    GdipSetClipRectI(gdip.memory, (INT)x, (INT)y, (INT)(w + 1), (INT)(h + 1), CombineModeReplace);\n}\n\nstatic void\nnk_gdip_stroke_line(short x0, short y0, short x1,\n    short y1, unsigned int line_thickness, struct nk_color col)\n{\n    GdipSetPenWidth(gdip.pen, (REAL)line_thickness);\n    GdipSetPenColor(gdip.pen, convert_color(col));\n    GdipDrawLineI(gdip.memory, gdip.pen, x0, y0, x1, y1);\n}\n\nstatic void\nnk_gdip_stroke_rect(short x, short y, unsigned short w,\n    unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)\n{\n    GdipSetPenWidth(gdip.pen, (REAL)line_thickness);\n    GdipSetPenColor(gdip.pen, convert_color(col));\n    if (r == 0) {\n        GdipDrawRectangleI(gdip.memory, gdip.pen, x, y, w, h);\n    } else {\n        INT d = 2 * r;\n        GdipDrawArcI(gdip.memory, gdip.pen, x, y, d, d, 180, 90);\n        GdipDrawLineI(gdip.memory, gdip.pen, x + r, y, x + w - r, y);\n        GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y, d, d, 270, 90);\n        GdipDrawLineI(gdip.memory, gdip.pen, x + w, y + r, x + w, y + h - r);\n        GdipDrawArcI(gdip.memory, gdip.pen, x + w - d, y + h - d, d, d, 0, 90);\n        GdipDrawLineI(gdip.memory, gdip.pen, x, y + r, x, y + h - r);\n        GdipDrawArcI(gdip.memory, gdip.pen, x, y + h - d, d, d, 90, 90);\n        GdipDrawLineI(gdip.memory, gdip.pen, x + r, y + h, x + w - r, y + h);\n    }\n}\n\nstatic void\nnk_gdip_fill_rect(short x, short y, unsigned short w,\n    unsigned short h, unsigned short r, struct nk_color col)\n{\n    GdipSetSolidFillColor(gdip.brush, convert_color(col));\n    if (r == 0) {\n        GdipFillRectangleI(gdip.memory, gdip.brush, x, y, w, h);\n    } else {\n        INT d = 2 * r;\n        GdipFillRectangleI(gdip.memory, gdip.brush, x + r, y, w - d, h);\n        GdipFillRectangleI(gdip.memory, gdip.brush, x, y + r, r, h - d);\n        GdipFillRectangleI(gdip.memory, gdip.brush, x + w - r, y + r, r, h - d);\n        GdipFillPieI(gdip.memory, gdip.brush, x, y, d, d, 180, 90);\n        GdipFillPieI(gdip.memory, gdip.brush, x + w - d, y, d, d, 270, 90);\n        GdipFillPieI(gdip.memory, gdip.brush, x + w - d, y + h - d, d, d, 0, 90);\n        GdipFillPieI(gdip.memory, gdip.brush, x, y + h - d, d, d, 90, 90);\n    }\n}\n\nstatic BOOL\nSetPoint(POINT *p, LONG x, LONG y)\n{\n    if (!p)\n        return FALSE;\n    p->x = x;\n    p->y = y;\n    return TRUE;\n}\n\nstatic void\nnk_gdip_fill_triangle(short x0, short y0, short x1,\n    short y1, short x2, short y2, struct nk_color col)\n{\n    POINT points[3];\n\n    SetPoint(&points[0], x0, y0);\n    SetPoint(&points[1], x1, y1);\n    SetPoint(&points[2], x2, y2);\n\n    GdipSetSolidFillColor(gdip.brush, convert_color(col));\n    GdipFillPolygonI(gdip.memory, gdip.brush, points, 3, FillModeAlternate);\n}\n\nstatic void\nnk_gdip_stroke_triangle(short x0, short y0, short x1,\n    short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)\n{\n    POINT points[4];\n\n    SetPoint(&points[0], x0, y0);\n    SetPoint(&points[1], x1, y1);\n    SetPoint(&points[2], x2, y2);\n    SetPoint(&points[3], x0, y0);\n\n    GdipSetPenWidth(gdip.pen, (REAL)line_thickness);\n    GdipSetPenColor(gdip.pen, convert_color(col));\n    GdipDrawPolygonI(gdip.memory, gdip.pen, points, 4);\n}\n\nstatic void\nnk_gdip_fill_polygon(const struct nk_vec2i *pnts, int count, struct nk_color col)\n{\n    int i = 0;\n    #define MAX_POINTS 64\n    POINT points[MAX_POINTS];\n    GdipSetSolidFillColor(gdip.brush, convert_color(col));\n    for (i = 0; i < count && i < MAX_POINTS; ++i) {\n        points[i].x = pnts[i].x;\n        points[i].y = pnts[i].y;\n    }\n    GdipFillPolygonI(gdip.memory, gdip.brush, points, i, FillModeAlternate);\n    #undef MAX_POINTS\n}\n\nstatic void\nnk_gdip_stroke_polygon(const struct nk_vec2i *pnts, int count,\n    unsigned short line_thickness, struct nk_color col)\n{\n    GdipSetPenWidth(gdip.pen, (REAL)line_thickness);\n    GdipSetPenColor(gdip.pen, convert_color(col));\n    if (count > 0) {\n        int i;\n        for (i = 1; i < count; ++i)\n            GdipDrawLineI(gdip.memory, gdip.pen, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);\n        GdipDrawLineI(gdip.memory, gdip.pen, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y);\n    }\n}\n\nstatic void\nnk_gdip_stroke_polyline(const struct nk_vec2i *pnts,\n    int count, unsigned short line_thickness, struct nk_color col)\n{\n    GdipSetPenWidth(gdip.pen, (REAL)line_thickness);\n    GdipSetPenColor(gdip.pen, convert_color(col));\n    if (count > 0) {\n        int i;\n        for (i = 1; i < count; ++i)\n            GdipDrawLineI(gdip.memory, gdip.pen, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);\n    }\n}\n\nstatic void\nnk_gdip_fill_circle(short x, short y, unsigned short w,\n    unsigned short h, struct nk_color col)\n{\n    GdipSetSolidFillColor(gdip.brush, convert_color(col));\n    GdipFillEllipseI(gdip.memory, gdip.brush, x, y, w, h);\n}\n\nstatic void\nnk_gdip_stroke_circle(short x, short y, unsigned short w,\n    unsigned short h, unsigned short line_thickness, struct nk_color col)\n{\n    GdipSetPenWidth(gdip.pen, (REAL)line_thickness);\n    GdipSetPenColor(gdip.pen, convert_color(col));\n    GdipDrawEllipseI(gdip.memory, gdip.pen, x, y, w, h);\n}\n\nstatic void\nnk_gdip_stroke_curve(struct nk_vec2i p1,\n    struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,\n    unsigned short line_thickness, struct nk_color col)\n{\n    GdipSetPenWidth(gdip.pen, (REAL)line_thickness);\n    GdipSetPenColor(gdip.pen, convert_color(col));\n    GdipDrawBezierI(gdip.memory, gdip.pen, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y);\n}\n\nstatic void\nnk_gdip_fill_arc(short cx, short cy, unsigned short r, float amin, float adelta, struct nk_color col)\n{\n    GdipSetSolidFillColor(gdip.brush, convert_color(col));\n    GdipFillPieI(gdip.memory, gdip.brush, cx - r, cy - r, r * 2, r * 2, amin * (180/M_PI), adelta * (180/M_PI));\n}\n\nstatic void\nnk_gdip_stroke_arc(short cx, short cy, unsigned short r, float amin, float adelta, unsigned short line_thickness, struct nk_color col)\n{\n    GdipSetPenWidth(gdip.pen, (REAL)line_thickness);\n    GdipSetPenColor(gdip.pen, convert_color(col));\n    GdipDrawPieI(gdip.memory, gdip.pen, cx - r, cy - r, r * 2, r * 2, amin * (180/M_PI), adelta * (180/M_PI));\n}\n\nstatic void\nnk_gdip_draw_text(short x, short y, unsigned short w, unsigned short h,\n    const char *text, int len, GdipFont *font, struct nk_color cbg, struct nk_color cfg)\n{\n    int wsize;\n    WCHAR* wstr;\n    RectF layout;\n\n    layout.X = x;\n    layout.Y = y;\n    layout.Width = w;\n    layout.Height = h;\n\n    if(!text || !font || !len) return;\n\n    wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);\n    wstr = (WCHAR*)_alloca(wsize * sizeof(wchar_t));\n    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);\n\n    GdipSetSolidFillColor(gdip.brush, convert_color(cfg));\n    GdipDrawString(gdip.memory, wstr, wsize, font->handle, &layout, gdip.format, gdip.brush);\n}\n\nstatic void\nnk_gdip_draw_image(short x, short y, unsigned short w, unsigned short h,\n    struct nk_image img, struct nk_color col)\n{\n    GpImage *image = img.handle.ptr;\n    GdipDrawImageRectI(gdip.memory, image, x, y, w, h);\n}\n\nstatic void\nnk_gdip_clear(struct nk_color col)\n{\n    GdipGraphicsClear(gdip.memory, convert_color(col));\n}\n\nstatic void\nnk_gdip_blit(GpGraphics *graphics)\n{\n    GdipDrawImageI(graphics, gdip.bitmap, 0, 0);\n}\n\nstatic struct nk_image\nnk_gdip_image_to_nk(GpImage *image) {\n    struct nk_image img;\n    UINT uwidth, uheight;\n    img = nk_image_ptr( (void*)image );\n    GdipGetImageHeight(image, &uheight);\n    GdipGetImageWidth(image, &uwidth);\n    img.h = uheight;\n    img.w = uwidth;\n    return img;\n}\n\nstruct nk_image\nnk_gdip_load_image_from_file(const WCHAR *filename)\n{\n    GpImage *image;\n    if (GdipLoadImageFromFile(filename, &image))\n        return nk_image_id(0);\n    return nk_gdip_image_to_nk(image);\n}\n\nstruct nk_image\nnk_gdip_load_image_from_memory(const void *membuf, nk_uint membufSize)\n{\n    GpImage* image;\n    GpStatus status;\n    IStream *stream = SHCreateMemStream((const BYTE*)membuf, membufSize);\n    if (!stream)\n        return nk_image_id(0);\n\n    status = GdipLoadImageFromStream(stream, &image);\n    stream->lpVtbl->Release(stream);\n\n    if (status)\n        return nk_image_id(0);\n\n    return nk_gdip_image_to_nk(image);\n}\n\nvoid\nnk_gdip_image_free(struct nk_image image)\n{\n    if (!image.handle.ptr)\n        return;\n    GdipDisposeImage(image.handle.ptr);\n}\n\nGdipFont*\nnk_gdipfont_create(const char *name, int size)\n{\n    GdipFont *font = (GdipFont*)calloc(1, sizeof(GdipFont));\n    GpFontFamily *family;\n\n    int wsize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);\n    WCHAR* wname = (WCHAR*)_alloca((wsize + 1) * sizeof(wchar_t));\n    MultiByteToWideChar(CP_UTF8, 0, name, -1, wname, wsize);\n    wname[wsize] = 0;\n\n    GdipCreateFontFamilyFromName(wname, NULL, &family);\n    GdipCreateFont(family, (REAL)size, FontStyleRegular, UnitPixel, &font->handle);\n    GdipDeleteFontFamily(family);\n\n    return font;\n}\n\nGpFontCollection*\nnk_gdip_getCurFontCollection(){\n    return gdip.fontCollection[gdip.curFontCollection];\n}\n\nGdipFont*\nnk_gdipfont_create_from_collection(int size){\n    GpFontFamily **families;\n    INT count;\n    GdipFont *font = (GdipFont*)calloc(1, sizeof(GdipFont));\n    if( GdipGetFontCollectionFamilyCount(nk_gdip_getCurFontCollection(), &count) ) return NULL;\n    families = (GpFontFamily**)calloc(1, sizeof(GpFontFamily*));\n    if( !families ) return NULL;\n    if( GdipGetFontCollectionFamilyList(nk_gdip_getCurFontCollection(), count, families, &count) ) return NULL;\n    if( count < 1 ) return NULL;\n    if( GdipCreateFont(families[count-1], (REAL)size, FontStyleRegular, UnitPixel, &font->handle) ) return NULL;\n    free(families);\n    gdip.curFontCollection++;\n    return font;\n}\n\nGdipFont*\nnk_gdipfont_create_from_memory(const void* membuf, int membufSize, int size)\n{\n    if( !nk_gdip_getCurFontCollection() )\n        if( GdipNewPrivateFontCollection(&gdip.fontCollection[gdip.curFontCollection]) ) return NULL;\n    if( GdipPrivateAddMemoryFont(nk_gdip_getCurFontCollection(), membuf, membufSize) ) return NULL;\n    return nk_gdipfont_create_from_collection(size);\n}\n\nGdipFont*\nnk_gdipfont_create_from_file(const WCHAR* filename, int size)\n{\n    if( !nk_gdip_getCurFontCollection() )\n        if( GdipNewPrivateFontCollection(&gdip.fontCollection[gdip.curFontCollection]) ) return NULL;\n    if( GdipPrivateAddFontFile(nk_gdip_getCurFontCollection(), filename) ) return NULL;\n    return nk_gdipfont_create_from_collection(size);\n}\n\nstatic float\nnk_gdipfont_get_text_width(nk_handle handle, float height, const char *text, int len)\n{\n    GdipFont *font = (GdipFont *)handle.ptr;\n    RectF layout = { 0.0f, 0.0f, 65536.0f, 65536.0f };\n    RectF bbox;\n    int wsize;\n    WCHAR* wstr;\n    if (!font || !text)\n        return 0;\n\n    (void)height;\n    wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);\n    wstr = (WCHAR*)_malloca(wsize * sizeof(wchar_t));\n    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);\n\n    GdipMeasureString(gdip.memory, wstr, wsize, font->handle, &layout, gdip.format, &bbox, NULL, NULL);\n    return bbox.Width;\n}\n\nvoid\nnk_gdipfont_del(GdipFont *font)\n{\n    if(!font) return;\n    GdipDeleteFont(font->handle);\n    free(font);\n}\n\nstatic void\nnk_gdip_clipboard_paste(nk_handle usr, struct nk_text_edit* edit)\n{\n    (void)usr;\n    if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))\n    {\n        HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);\n        if (mem)\n        {\n            SIZE_T size = GlobalSize(mem) - 1;\n            if (size)\n            {\n                LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);\n                if (wstr)\n                {\n                    int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), NULL, 0, NULL, NULL);\n                    if (utf8size)\n                    {\n                        char* utf8 = (char*)malloc(utf8size);\n                        if (utf8)\n                        {\n                            WideCharToMultiByte(CP_UTF8, 0, wstr, (int)(size / sizeof(wchar_t)), utf8, utf8size, NULL, NULL);\n                            nk_textedit_paste(edit, utf8, utf8size);\n                            free(utf8);\n                        }\n                    }\n                    GlobalUnlock(mem);\n                }\n            }\n        }\n        CloseClipboard();\n    }\n}\n\nstatic void\nnk_gdip_clipboard_copy(nk_handle usr, const char* text, int len)\n{\n    if (OpenClipboard(NULL))\n    {\n        int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);\n        if (wsize)\n        {\n            HGLOBAL mem = (HGLOBAL)GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));\n            if (mem)\n            {\n                wchar_t* wstr = (wchar_t*)GlobalLock(mem);\n                if (wstr)\n                {\n                    MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);\n                    wstr[wsize] = 0;\n                    GlobalUnlock(mem);\n\n                    SetClipboardData(CF_UNICODETEXT, mem);\n                }\n            }\n        }\n        CloseClipboard();\n    }\n}\n\nNK_API struct nk_context*\nnk_gdip_init(HWND hwnd, unsigned int width, unsigned int height)\n{\n    int i;\n    GdiplusStartupInput startup = { 1, NULL, FALSE, TRUE };\n    GdiplusStartup(&gdip.token, &startup, NULL);\n\n    GdipCreateFromHWND(hwnd, &gdip.window);\n    GdipCreateBitmapFromGraphics(width, height, gdip.window, &gdip.bitmap);\n    GdipGetImageGraphicsContext(gdip.bitmap, &gdip.memory);\n    GdipCreatePen1(0, 1.0f, UnitPixel, &gdip.pen);\n    GdipCreateSolidFill(0, &gdip.brush);\n    GdipStringFormatGetGenericTypographic(&gdip.format);\n    GdipSetStringFormatFlags(gdip.format, StringFormatFlagsNoFitBlackBox |\n        StringFormatFlagsMeasureTrailingSpaces | StringFormatFlagsNoWrap |\n        StringFormatFlagsNoClip);\n\n    for(i=0; i< sizeof(gdip.fontCollection)/sizeof(gdip.fontCollection[0]); i++)\n        gdip.fontCollection[i] = NULL;\n    nk_init_default(&gdip.ctx, NULL);\n    gdip.ctx.clip.copy = nk_gdip_clipboard_copy;\n    gdip.ctx.clip.paste = nk_gdip_clipboard_paste;\n    gdip.curFontCollection = 0;\n    return &gdip.ctx;\n}\n\nNK_API void\nnk_gdip_set_font(GdipFont *gdipfont)\n{\n    struct nk_user_font *font = &gdipfont->nk;\n    font->userdata = nk_handle_ptr(gdipfont);\n    GdipGetFontSize(gdipfont->handle, &font->height);\n    font->width = nk_gdipfont_get_text_width;\n    nk_style_set_font(&gdip.ctx, font);\n}\n\nNK_API int\nnk_gdip_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)\n{\n    static int insert_toggle = 0;\n    switch (msg)\n    {\n    case WM_SIZE:\n        if (gdip.window)\n        {\n            unsigned int width = LOWORD(lparam);\n            unsigned int height = HIWORD(lparam);\n            GdipDeleteGraphics(gdip.window);\n            GdipDeleteGraphics(gdip.memory);\n            GdipDisposeImage(gdip.bitmap);\n            GdipCreateFromHWND(wnd, &gdip.window);\n            GdipCreateBitmapFromGraphics(width, height, gdip.window, &gdip.bitmap);\n            GdipGetImageGraphicsContext(gdip.bitmap, &gdip.memory);\n        }\n        break;\n\n    case WM_PAINT:\n    {\n        PAINTSTRUCT paint;\n        HDC dc = BeginPaint(wnd, &paint);\n        GpGraphics *graphics;\n        GdipCreateFromHDC(dc, &graphics);\n        nk_gdip_blit(graphics);\n        GdipDeleteGraphics(graphics);\n        EndPaint(wnd, &paint);\n        return 1;\n    }\n\n    case WM_KEYDOWN:\n    case WM_KEYUP:\n    case WM_SYSKEYDOWN:\n    case WM_SYSKEYUP:\n    {\n        int down = !((lparam >> 31) & 1);\n        int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);\n\n        switch (wparam)\n        {\n        case VK_SHIFT:\n        case VK_LSHIFT:\n        case VK_RSHIFT:\n            nk_input_key(&gdip.ctx, NK_KEY_SHIFT, down);\n            return 1;\n\n        case VK_DELETE:\n            nk_input_key(&gdip.ctx, NK_KEY_DEL, down);\n            return 1;\n\n        case VK_RETURN:\n        case VK_SEPARATOR:\n            nk_input_key(&gdip.ctx, NK_KEY_ENTER, down);\n            return 1;\n\n        case VK_TAB:\n            nk_input_key(&gdip.ctx, NK_KEY_TAB, down);\n            return 1;\n\n        case VK_LEFT:\n            if (ctrl)\n                nk_input_key(&gdip.ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else\n                nk_input_key(&gdip.ctx, NK_KEY_LEFT, down);\n            return 1;\n\n        case VK_RIGHT:\n            if (ctrl)\n                nk_input_key(&gdip.ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else\n                nk_input_key(&gdip.ctx, NK_KEY_RIGHT, down);\n            return 1;\n\n        case VK_BACK:\n            nk_input_key(&gdip.ctx, NK_KEY_BACKSPACE, down);\n            return 1;\n\n        case VK_HOME:\n            nk_input_key(&gdip.ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(&gdip.ctx, NK_KEY_SCROLL_START, down);\n            return 1;\n\n        case VK_END:\n            nk_input_key(&gdip.ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(&gdip.ctx, NK_KEY_SCROLL_END, down);\n            return 1;\n\n        case VK_NEXT:\n            nk_input_key(&gdip.ctx, NK_KEY_SCROLL_DOWN, down);\n            return 1;\n\n        case VK_PRIOR:\n            nk_input_key(&gdip.ctx, NK_KEY_SCROLL_UP, down);\n            return 1;\n\n        case VK_ESCAPE:\n            nk_input_key(&gdip.ctx, NK_KEY_TEXT_RESET_MODE, down);\n            return 1;\n\n        case VK_INSERT:\n        /* Only switch on release to avoid repeat issues\n         * kind of confusing since we have to negate it but we're already\n         * hacking it since Nuklear treats them as two separate keys rather\n         * than a single toggle state */\n            if (!down) {\n                insert_toggle = !insert_toggle;\n                if (insert_toggle) {\n                    nk_input_key(&gdip.ctx, NK_KEY_TEXT_INSERT_MODE, !down);\n                    /* nk_input_key(&gdip.ctx, NK_KEY_TEXT_REPLACE_MODE, down); */\n                } else {\n                    nk_input_key(&gdip.ctx, NK_KEY_TEXT_REPLACE_MODE, !down);\n                    /* nk_input_key(&gdip.ctx, NK_KEY_TEXT_INSERT_MODE, down); */\n                }\n            }\n            return 1;\n\n        case 'A':\n            if (ctrl) {\n                nk_input_key(&gdip.ctx, NK_KEY_TEXT_SELECT_ALL, down);\n                return 1;\n            }\n            break;\n\n        case 'B':\n            if (ctrl) {\n                nk_input_key(&gdip.ctx, NK_KEY_TEXT_LINE_START, down);\n                return 1;\n            }\n            break;\n\n        case 'E':\n            if (ctrl) {\n                nk_input_key(&gdip.ctx, NK_KEY_TEXT_LINE_END, down);\n                return 1;\n            }\n            break;\n\n\n        case 'C':\n            if (ctrl) {\n                nk_input_key(&gdip.ctx, NK_KEY_COPY, down);\n                return 1;\n            }\n            break;\n\n        case 'V':\n            if (ctrl) {\n                nk_input_key(&gdip.ctx, NK_KEY_PASTE, down);\n                return 1;\n            }\n            break;\n\n        case 'X':\n            if (ctrl) {\n                nk_input_key(&gdip.ctx, NK_KEY_CUT, down);\n                return 1;\n            }\n            break;\n\n        case 'Z':\n            if (ctrl) {\n                nk_input_key(&gdip.ctx, NK_KEY_TEXT_UNDO, down);\n                return 1;\n            }\n            break;\n\n        case 'R':\n            if (ctrl) {\n                nk_input_key(&gdip.ctx, NK_KEY_TEXT_REDO, down);\n                return 1;\n            }\n            break;\n        }\n        return 0;\n    }\n\n    case WM_CHAR:\n        if (wparam >= 32)\n        {\n            nk_input_unicode(&gdip.ctx, (nk_rune)wparam);\n            return 1;\n        }\n        break;\n\n    case WM_LBUTTONDOWN:\n        nk_input_button(&gdip.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_LBUTTONUP:\n        nk_input_button(&gdip.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        nk_input_button(&gdip.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_RBUTTONDOWN:\n        nk_input_button(&gdip.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_RBUTTONUP:\n        nk_input_button(&gdip.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_MBUTTONDOWN:\n        nk_input_button(&gdip.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        SetCapture(wnd);\n        return 1;\n\n    case WM_MBUTTONUP:\n        nk_input_button(&gdip.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n        ReleaseCapture();\n        return 1;\n\n    case WM_XBUTTONDOWN:\n        switch (GET_XBUTTON_WPARAM(wparam)) {\n        case XBUTTON1:\n            nk_input_button(&gdip.ctx, NK_BUTTON_X1, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n            break;\n        case XBUTTON2:\n            nk_input_button(&gdip.ctx, NK_BUTTON_X2, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n            break;\n        }\n        SetCapture(wnd);\n        return 1;\n\n    case WM_XBUTTONUP:\n        switch (GET_XBUTTON_WPARAM(wparam)) {\n        case XBUTTON1:\n            nk_input_button(&gdip.ctx, NK_BUTTON_X1, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n            break;\n        case XBUTTON2:\n            nk_input_button(&gdip.ctx, NK_BUTTON_X2, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);\n            break;\n        }\n        ReleaseCapture();\n        return 1;\n\n    case WM_MOUSEWHEEL:\n        nk_input_scroll(&gdip.ctx, nk_vec2(0,(float)(short)HIWORD(wparam) / WHEEL_DELTA));\n        return 1;\n\n    case WM_MOUSEMOVE:\n        nk_input_motion(&gdip.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));\n        return 1;\n\n    case WM_LBUTTONDBLCLK:\n        nk_input_button(&gdip.ctx, NK_BUTTON_DOUBLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);\n        return 1;\n    }\n\n    return 0;\n}\n\nNK_API void\nnk_gdip_shutdown(void)\n{\n    int i;\n    for(i=0; i< gdip.curFontCollection; i++)\n        GdipDeletePrivateFontCollection( &gdip.fontCollection[i] );\n    GdipDeleteGraphics(gdip.window);\n    GdipDeleteGraphics(gdip.memory);\n    GdipDisposeImage(gdip.bitmap);\n    GdipDeletePen(gdip.pen);\n    GdipDeleteBrush(gdip.brush);\n    GdipDeleteStringFormat(gdip.format);\n    GdiplusShutdown(gdip.token);\n\n    nk_free(&gdip.ctx);\n}\n\nNK_API void\nnk_gdip_prerender_gui(enum nk_anti_aliasing AA)\n{\n    const struct nk_command *cmd;\n\n    GdipSetTextRenderingHint(gdip.memory, AA != NK_ANTI_ALIASING_OFF ?\n        TextRenderingHintClearTypeGridFit : TextRenderingHintSingleBitPerPixelGridFit);\n    GdipSetSmoothingMode(gdip.memory, AA != NK_ANTI_ALIASING_OFF ?\n        SmoothingModeHighQuality : SmoothingModeNone);\n\n    nk_foreach(cmd, &gdip.ctx)\n    {\n        switch (cmd->type) {\n        case NK_COMMAND_NOP: break;\n        case NK_COMMAND_SCISSOR: {\n            const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;\n            nk_gdip_scissor(s->x, s->y, s->w, s->h);\n        } break;\n        case NK_COMMAND_LINE: {\n            const struct nk_command_line *l = (const struct nk_command_line *)cmd;\n            nk_gdip_stroke_line(l->begin.x, l->begin.y, l->end.x,\n                l->end.y, l->line_thickness, l->color);\n        } break;\n        case NK_COMMAND_RECT: {\n            const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;\n            nk_gdip_stroke_rect(r->x, r->y, r->w, r->h,\n                (unsigned short)r->rounding, r->line_thickness, r->color);\n        } break;\n        case NK_COMMAND_RECT_FILLED: {\n            const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;\n            nk_gdip_fill_rect(r->x, r->y, r->w, r->h,\n                (unsigned short)r->rounding, r->color);\n        } break;\n        case NK_COMMAND_CIRCLE: {\n            const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;\n            nk_gdip_stroke_circle(c->x, c->y, c->w, c->h, c->line_thickness, c->color);\n        } break;\n        case NK_COMMAND_CIRCLE_FILLED: {\n            const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;\n            nk_gdip_fill_circle(c->x, c->y, c->w, c->h, c->color);\n        } break;\n        case NK_COMMAND_TRIANGLE: {\n            const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;\n            nk_gdip_stroke_triangle(t->a.x, t->a.y, t->b.x, t->b.y,\n                t->c.x, t->c.y, t->line_thickness, t->color);\n        } break;\n        case NK_COMMAND_TRIANGLE_FILLED: {\n            const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;\n            nk_gdip_fill_triangle(t->a.x, t->a.y, t->b.x, t->b.y,\n                t->c.x, t->c.y, t->color);\n        } break;\n        case NK_COMMAND_POLYGON: {\n            const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd;\n            nk_gdip_stroke_polygon(p->points, p->point_count, p->line_thickness,p->color);\n        } break;\n        case NK_COMMAND_POLYGON_FILLED: {\n            const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;\n            nk_gdip_fill_polygon(p->points, p->point_count, p->color);\n        } break;\n        case NK_COMMAND_POLYLINE: {\n            const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;\n            nk_gdip_stroke_polyline(p->points, p->point_count, p->line_thickness, p->color);\n        } break;\n        case NK_COMMAND_TEXT: {\n            const struct nk_command_text *t = (const struct nk_command_text*)cmd;\n            nk_gdip_draw_text(t->x, t->y, t->w, t->h,\n                (const char*)t->string, t->length,\n                (GdipFont*)t->font->userdata.ptr,\n                t->background, t->foreground);\n        } break;\n        case NK_COMMAND_CURVE: {\n            const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;\n            nk_gdip_stroke_curve(q->begin, q->ctrl[0], q->ctrl[1],\n                q->end, q->line_thickness, q->color);\n        } break;\n        case NK_COMMAND_IMAGE: {\n            const struct nk_command_image *i = (const struct nk_command_image *)cmd;\n            nk_gdip_draw_image(i->x, i->y, i->w, i->h, i->img, i->col);\n        } break;\n        case NK_COMMAND_ARC: {\n            const struct nk_command_arc *i = (const struct nk_command_arc *)cmd;\n            nk_gdip_stroke_arc(i->cx, i->cy, i->r, i->a[0], i->a[1], i->line_thickness, i->color);\n        } break;\n        case NK_COMMAND_ARC_FILLED: {\n            const struct nk_command_arc_filled *i = (const struct nk_command_arc_filled *)cmd;\n            nk_gdip_fill_arc(i->cx, i->cy, i->r, i->a[0], i->a[1], i->color);\n        } break;\n        case NK_COMMAND_RECT_MULTI_COLOR:\n        default: break;\n        }\n    }\n}\n\nNK_API void\nnk_gdip_render_gui(enum nk_anti_aliasing AA)\n{\n    nk_gdip_prerender_gui(AA);\n    nk_gdip_blit(gdip.window);\n    nk_clear(&gdip.ctx);\n}\n\nNK_API void\nnk_gdip_render(enum nk_anti_aliasing AA, struct nk_color clear)\n{\n    nk_gdip_clear(clear);\n    nk_gdip_render_gui(AA);\n}\n\n#endif\n"
  },
  {
    "path": "demo/glfw_opengl2/Makefile",
    "content": "# Install\nBIN = demo\n\n# Flags\nCFLAGS += -std=c99 -Wall -Wextra -pedantic\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\nifeq ($(OS),Windows_NT)\nBIN := $(BIN).exe\nLIBS = -lglfw3 -lopengl32 -lm -lGLU32\nelse\n\tUNAME_S := $(shell uname -s)\n\tifeq ($(UNAME_S),Darwin)\n\t\tLIBS := -lglfw3 -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -lm -lGLEW -L/usr/local/lib\n\telse\n\t\tLIBS = -lglfw -lGL -lm -lGLU\n\tendif\nendif\n\n$(BIN):\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)\n"
  },
  {
    "path": "demo/glfw_opengl2/main.c",
    "content": "/* nuklear - v1.32.0 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <limits.h>\n#include <time.h>\n\n#include <GLFW/glfw3.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_GLFW_GL2_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_glfw_gl2.h\"\n\n#define STB_IMAGE_IMPLEMENTATION\n#include \"../../demo/common/filebrowser/stb_image.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/* #define INCLUDE_ALL          */\n/* #define INCLUDE_STYLE        */\n/* #define INCLUDE_CALCULATOR   */\n/* #define INCLUDE_CANVAS       */\n/* #define INCLUDE_FILE_BROWSER */\n#define INCLUDE_OVERVIEW\n/* #define INCLUDE_CONFIGURATOR */\n/* #define INCLUDE_NODE_EDITOR  */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_FILE_BROWSER\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_FILE_BROWSER\n  #include \"../../demo/common/file_browser.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nstatic void error_callback(int e, const char *d)\n{printf(\"Error %d: %s\\n\", e, d);}\n\nint main(void)\n{\n    /* Platform */\n    static GLFWwindow *win;\n    int width = 0, height = 0;\n\n    /* GUI */\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n#ifdef INCLUDE_FILE_BROWSER\n    struct file_browser browser;\n    struct media media;\n#endif\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    /* GLFW */\n    glfwSetErrorCallback(error_callback);\n    if (!glfwInit()) {\n        fprintf(stdout, \"[GFLW] failed to init!\\n\");\n        exit(1);\n    }\n    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, \"Demo\", NULL, NULL);\n    glfwMakeContextCurrent(win);\n    glfwGetWindowSize(win, &width, &height);\n\n    /* GUI */\n    ctx = nk_glfw3_init(win, NK_GLFW3_INSTALL_CALLBACKS);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {struct nk_font_atlas *atlas;\n    nk_glfw3_font_stash_begin(&atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Roboto-Regular.ttf\", 14, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_glfw3_font_stash_end();\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &droid->handle);*/}\n\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n\n    #ifdef INCLUDE_FILE_BROWSER\n    /* icons */\n    glEnable(GL_TEXTURE_2D);\n    media.icons.home = icon_load(\"../../demo/common/filebrowser/icon/home.png\");\n    media.icons.directory = icon_load(\"../../demo/common/filebrowser/icon/directory.png\");\n    media.icons.computer = icon_load(\"../../demo/common/filebrowser/icon/computer.png\");\n    media.icons.desktop = icon_load(\"../../demo/common/filebrowser/icon/desktop.png\");\n    media.icons.default_file = icon_load(\"../../demo/common/filebrowser/icon/default.png\");\n    media.icons.text_file = icon_load(\"../../demo/common/filebrowser/icon/text.png\");\n    media.icons.music_file = icon_load(\"../../demo/common/filebrowser/icon/music.png\");\n    media.icons.font_file =  icon_load(\"../../demo/common/filebrowser/icon/font.png\");\n    media.icons.img_file = icon_load(\"../../demo/common/filebrowser/icon/img.png\");\n    media.icons.movie_file = icon_load(\"../../demo/common/filebrowser/icon/movie.png\");\n    media_init(&media);\n\n    file_browser_init(&browser, &media);\n    #endif\n\n    while (!glfwWindowShouldClose(win))\n    {\n        /* Input */\n        glfwPollEvents();\n        nk_glfw3_new_frame();\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_FILE_BROWSER\n          file_browser_run(&browser, ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        glfwGetWindowSize(win, &width, &height);\n        glViewport(0, 0, width, height);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(bg.r, bg.g, bg.b, bg.a);\n        /* IMPORTANT: `nk_glfw_render` modifies some global OpenGL state\n         * with blending, scissor, face culling and depth test and defaults everything\n         * back into a default state. Make sure to either save and restore or\n         * reset your own state after drawing rendering the UI. */\n        nk_glfw3_render(NK_ANTI_ALIASING_ON);\n        glfwSwapBuffers(win);\n    }\n\n    #ifdef INCLUDE_FILE_BROWSER\n    glDeleteTextures(1,(const GLuint*)&media.icons.home.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.directory.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.computer.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.desktop.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.default_file.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.text_file.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.music_file.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.font_file.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.img_file.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.movie_file.handle.id);\n\n    file_browser_free(&browser);\n    #endif\n\n    nk_glfw3_shutdown();\n    glfwTerminate();\n    return 0;\n}\n"
  },
  {
    "path": "demo/glfw_opengl2/nuklear_glfw_gl2.h",
    "content": "/*\n * Nuklear - v1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2017 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_GLFW_GL2_H_\n#define NK_GLFW_GL2_H_\n\n#include <GLFW/glfw3.h>\n\nenum nk_glfw_init_state{\n    NK_GLFW3_DEFAULT = 0,\n    NK_GLFW3_INSTALL_CALLBACKS\n};\nNK_API struct nk_context*   nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state);\nNK_API void                 nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void                 nk_glfw3_font_stash_end(void);\n\nNK_API void                 nk_glfw3_new_frame(void);\nNK_API void                 nk_glfw3_render(enum nk_anti_aliasing);\nNK_API void                 nk_glfw3_shutdown(void);\n\nNK_API void                 nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);\nNK_API void                 nk_glfw3_key_callback(GLFWwindow *win, int key, int scancode, int action, int mods);\nNK_API void                 nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);\nNK_API void                 nk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods);\n\n#endif\n\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_GLFW_GL2_IMPLEMENTATION\n#include <string.h>\n#include <stdlib.h>\n\n#ifndef NK_GLFW_TEXT_MAX\n#define NK_GLFW_TEXT_MAX 256\n#endif\n#ifndef NK_GLFW_DOUBLE_CLICK_LO\n#define NK_GLFW_DOUBLE_CLICK_LO 0.02\n#endif\n#ifndef NK_GLFW_DOUBLE_CLICK_HI\n#define NK_GLFW_DOUBLE_CLICK_HI 0.2\n#endif\n\nstruct nk_glfw_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint font_tex;\n};\n\nstruct nk_glfw_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstatic struct nk_glfw {\n    GLFWwindow *win;\n    int width, height;\n    int display_width, display_height;\n    struct nk_glfw_device ogl;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    struct nk_vec2 fb_scale;\n    unsigned int text[NK_GLFW_TEXT_MAX];\n    nk_char key_events[NK_KEY_MAX];\n    int text_len;\n    struct nk_vec2 scroll;\n    double last_button_click;\n    int is_double_click_down;\n    struct nk_vec2 double_click_pos;\n    float delta_time_seconds_last;\n} glfw;\n\nNK_INTERN void\nnk_glfw3_device_upload_atlas(const void *image, int width, int height)\n{\n    struct nk_glfw_device *dev = &glfw.ogl;\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nNK_API void\nnk_glfw3_render(enum nk_anti_aliasing AA)\n{\n    /* setup global state */\n    struct nk_glfw_device *dev = &glfw.ogl;\n    glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glEnable(GL_BLEND);\n    glEnable(GL_TEXTURE_2D);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n    /* setup viewport/project */\n    glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height);\n    glMatrixMode(GL_PROJECTION);\n    glPushMatrix();\n    glLoadIdentity();\n    glOrtho(0.0f, glfw.width, glfw.height, 0.0f, -1.0f, 1.0f);\n    glMatrixMode(GL_MODELVIEW);\n    glPushMatrix();\n    glLoadIdentity();\n\n    glEnableClientState(GL_VERTEX_ARRAY);\n    glEnableClientState(GL_TEXTURE_COORD_ARRAY);\n    glEnableClientState(GL_COLOR_ARRAY);\n    {\n        GLsizei vs = sizeof(struct nk_glfw_vertex);\n        size_t vp = offsetof(struct nk_glfw_vertex, position);\n        size_t vt = offsetof(struct nk_glfw_vertex, uv);\n        size_t vc = offsetof(struct nk_glfw_vertex, col);\n\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        const nk_draw_index *offset = NULL;\n        struct nk_buffer vbuf, ebuf;\n\n        /* fill convert configuration */\n        struct nk_convert_config config;\n        static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n            {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},\n            {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},\n            {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},\n            {NK_VERTEX_LAYOUT_END}\n        };\n        memset(&config, 0, sizeof(config));\n        config.vertex_layout = vertex_layout;\n        config.vertex_size = sizeof(struct nk_glfw_vertex);\n        config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);\n        config.tex_null = dev->tex_null;\n        config.circle_segment_count = 22;\n        config.curve_segment_count = 22;\n        config.arc_segment_count = 22;\n        config.global_alpha = 1.0f;\n        config.shape_AA = AA;\n        config.line_AA = AA;\n\n        /* convert shapes into vertexes */\n        nk_buffer_init_default(&vbuf);\n        nk_buffer_init_default(&ebuf);\n        nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n\n        /* setup vertex buffer pointer */\n        {const void *vertices = nk_buffer_memory_const(&vbuf);\n        glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp));\n        glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt));\n        glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));}\n\n        /* iterate over and execute each draw command */\n        offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);\n        nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds)\n        {\n            if (!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor(\n                (GLint)(cmd->clip_rect.x * glfw.fb_scale.x),\n                (GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y),\n                (GLint)(cmd->clip_rect.w * glfw.fb_scale.x),\n                (GLint)(cmd->clip_rect.h * glfw.fb_scale.y));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(&glfw.ctx);\n        nk_buffer_clear(&dev->cmds);\n        nk_buffer_free(&vbuf);\n        nk_buffer_free(&ebuf);\n    }\n\n    /* default OpenGL state */\n    glDisableClientState(GL_VERTEX_ARRAY);\n    glDisableClientState(GL_TEXTURE_COORD_ARRAY);\n    glDisableClientState(GL_COLOR_ARRAY);\n\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glDisable(GL_SCISSOR_TEST);\n    glDisable(GL_BLEND);\n    glDisable(GL_TEXTURE_2D);\n\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glMatrixMode(GL_MODELVIEW);\n    glPopMatrix();\n    glMatrixMode(GL_PROJECTION);\n    glPopMatrix();\n    glPopAttrib();\n}\n\nNK_API void\nnk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint)\n{\n    (void)win;\n    if (glfw.text_len < NK_GLFW_TEXT_MAX)\n        glfw.text[glfw.text_len++] = codepoint;\n}\n\nNK_API void\nnk_glfw3_key_callback(GLFWwindow *win, int key, int scancode, int action, int mods)\n{\n    static int insert_toggle = 0;\n    /*\n     * convert GLFW_REPEAT to down (technically GLFW_RELEASE, GLFW_PRESS, GLFW_REPEAT are\n     * already 0, 1, 2 but just to be clearer)\n     */\n    nk_char a = (action == GLFW_RELEASE) ? nk_false : nk_true;\n\n    NK_UNUSED(win);\n    NK_UNUSED(scancode);\n    NK_UNUSED(mods);\n\n    switch (key) {\n    case GLFW_KEY_DELETE:    glfw.key_events[NK_KEY_DEL] = a; break;\n    case GLFW_KEY_TAB:       glfw.key_events[NK_KEY_TAB] = a; break;\n    case GLFW_KEY_BACKSPACE: glfw.key_events[NK_KEY_BACKSPACE] = a; break;\n    case GLFW_KEY_UP:        glfw.key_events[NK_KEY_UP] = a; break;\n    case GLFW_KEY_DOWN:      glfw.key_events[NK_KEY_DOWN] = a; break;\n    case GLFW_KEY_LEFT:      glfw.key_events[NK_KEY_LEFT] = a; break;\n    case GLFW_KEY_RIGHT:     glfw.key_events[NK_KEY_RIGHT] = a; break;\n    case GLFW_KEY_ESCAPE:    glfw.key_events[NK_KEY_TEXT_RESET_MODE] = a; break;\n\n    case GLFW_KEY_PAGE_UP:   glfw.key_events[NK_KEY_SCROLL_UP] = a; break;\n    case GLFW_KEY_PAGE_DOWN: glfw.key_events[NK_KEY_SCROLL_DOWN] = a; break;\n\n    /* have to add all keys used for nuklear to get correct repeat behavior\n     * NOTE these are scancodes so your custom layout won't matter unfortunately\n     * Also while including everything will prevent unnecessary input calls,\n     * only the ones with visible effects really matter, ie paste, undo, redo\n     * selecting all, copying or cutting 40 times before you release the keys\n     * doesn't actually cause any visible problems */\n\n    case GLFW_KEY_C:         glfw.key_events[NK_KEY_COPY] = a; break;\n    case GLFW_KEY_V:         glfw.key_events[NK_KEY_PASTE] = a; break;\n    case GLFW_KEY_X:         glfw.key_events[NK_KEY_CUT] = a; break;\n    case GLFW_KEY_Z:         glfw.key_events[NK_KEY_TEXT_UNDO] = a; break;\n    case GLFW_KEY_R:         glfw.key_events[NK_KEY_TEXT_REDO] = a; break;\n    case GLFW_KEY_B:         glfw.key_events[NK_KEY_TEXT_LINE_START] = a; break;\n    case GLFW_KEY_E:         glfw.key_events[NK_KEY_TEXT_LINE_END] = a; break;\n    case GLFW_KEY_A:         glfw.key_events[NK_KEY_TEXT_SELECT_ALL] = a; break;\n\n    case GLFW_KEY_ENTER:\n    case GLFW_KEY_KP_ENTER:\n        glfw.key_events[NK_KEY_ENTER] = a;\n        break;\n    case GLFW_KEY_INSERT:\n        /* Only switch on release to avoid repeat issues\n         * kind of confusing since we have to negate it but we're already\n         * hacking it since Nuklear treats them as two separate keys rather\n         * than a single toggle state */\n        if (!a) {\n            insert_toggle = !insert_toggle;\n            if (insert_toggle) {\n                glfw.key_events[NK_KEY_TEXT_INSERT_MODE] = !a;\n                /* glfw.key_events[NK_KEY_TEXT_REPLACE_MODE] = a; */\n            } else {\n                /* glfw.key_events[NK_KEY_TEXT_INSERT_MODE] = a; */\n                glfw.key_events[NK_KEY_TEXT_REPLACE_MODE] = !a;\n            }\n        }\n        break;\n    default:\n        ;\n    }\n}\n\nNK_API void\nnk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff)\n{\n    (void)win; (void)xoff;\n    glfw.scroll.x += (float)xoff;\n    glfw.scroll.y += (float)yoff;\n}\n\nNK_API void\nnk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)\n{\n    double x, y;\n    NK_UNUSED(mods);\n    if (button != GLFW_MOUSE_BUTTON_LEFT) return;\n    glfwGetCursorPos(window, &x, &y);\n    if (action == GLFW_PRESS)  {\n        double dt = glfwGetTime() - glfw.last_button_click;\n        if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) {\n            glfw.is_double_click_down = nk_true;\n            glfw.double_click_pos = nk_vec2((float)x, (float)y);\n        }\n        glfw.last_button_click = glfwGetTime();\n    } else glfw.is_double_click_down = nk_false;\n}\n\nNK_INTERN void\nnk_glfw3_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    const char *text = glfwGetClipboardString(glfw.win);\n    if (text) nk_textedit_paste(edit, text, nk_strlen(text));\n    (void)usr;\n}\n\nNK_INTERN void\nnk_glfw3_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    char *str = 0;\n    (void)usr;\n    if (!len) return;\n    str = (char*)malloc((size_t)len+1);\n    if (!str) return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n    glfwSetClipboardString(glfw.win, str);\n    free(str);\n}\n\nNK_API struct nk_context*\nnk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state)\n{\n    glfw.win = win;\n    if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {\n        glfwSetScrollCallback(win, nk_gflw3_scroll_callback);\n        glfwSetCharCallback(win, nk_glfw3_char_callback);\n        glfwSetKeyCallback(win, nk_glfw3_key_callback);\n        glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback);\n    }\n    nk_init_default(&glfw.ctx, 0);\n    glfw.ctx.clip.copy = nk_glfw3_clipboard_copy;\n    glfw.ctx.clip.paste = nk_glfw3_clipboard_paste;\n    glfw.ctx.clip.userdata = nk_handle_ptr(0);\n    nk_buffer_init_default(&glfw.ogl.cmds);\n\n    glfw.is_double_click_down = nk_false;\n    glfw.double_click_pos = nk_vec2(0, 0);\n\n    glfw.delta_time_seconds_last = (float)glfwGetTime();\n\n    return &glfw.ctx;\n}\n\nNK_API void\nnk_glfw3_font_stash_begin(struct nk_font_atlas **atlas)\n{\n    nk_font_atlas_init_default(&glfw.atlas);\n    nk_font_atlas_begin(&glfw.atlas);\n    *atlas = &glfw.atlas;\n}\n\nNK_API void\nnk_glfw3_font_stash_end(void)\n{\n    const void *image; int w, h;\n    image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_glfw3_device_upload_atlas(image, w, h);\n    nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex), &glfw.ogl.tex_null);\n    if (glfw.atlas.default_font)\n        nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle);\n}\n\nNK_API void\nnk_glfw3_new_frame(void)\n{\n    int i;\n    double x, y;\n    struct nk_context *ctx = &glfw.ctx;\n    struct GLFWwindow *win = glfw.win;\n    nk_char* k_state = glfw.key_events;\n\n    /* update the timer */\n    float delta_time_now = (float)glfwGetTime();\n    glfw.ctx.delta_time_seconds = delta_time_now - glfw.delta_time_seconds_last;\n    glfw.delta_time_seconds_last = delta_time_now;\n\n    glfwGetWindowSize(win, &glfw.width, &glfw.height);\n    glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height);\n    glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width;\n    glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height;\n\n    nk_input_begin(ctx);\n    for (i = 0; i < glfw.text_len; ++i)\n        nk_input_unicode(ctx, glfw.text[i]);\n\n    /* optional grabbing behavior */\n    if (ctx->input.mouse.grab)\n        glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);\n    else if (ctx->input.mouse.ungrab)\n        glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);\n\n    if (k_state[NK_KEY_DEL] >= 0) nk_input_key(ctx, NK_KEY_DEL, k_state[NK_KEY_DEL]);\n    if (k_state[NK_KEY_ENTER] >= 0) nk_input_key(ctx, NK_KEY_ENTER, k_state[NK_KEY_ENTER]);\n    if (k_state[NK_KEY_TEXT_RESET_MODE] >= 0) nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, k_state[NK_KEY_TEXT_RESET_MODE]);\n\n    if (k_state[NK_KEY_TAB] >= 0) nk_input_key(ctx, NK_KEY_TAB, k_state[NK_KEY_TAB]);\n    if (k_state[NK_KEY_BACKSPACE] >= 0) nk_input_key(ctx, NK_KEY_BACKSPACE, k_state[NK_KEY_BACKSPACE]);\n    if (k_state[NK_KEY_UP] >= 0) nk_input_key(ctx, NK_KEY_UP, k_state[NK_KEY_UP]);\n    if (k_state[NK_KEY_DOWN] >= 0) nk_input_key(ctx, NK_KEY_DOWN, k_state[NK_KEY_DOWN]);\n    if (k_state[NK_KEY_SCROLL_UP] >= 0) nk_input_key(ctx, NK_KEY_SCROLL_UP, k_state[NK_KEY_SCROLL_UP]);\n    if (k_state[NK_KEY_SCROLL_DOWN] >= 0) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, k_state[NK_KEY_SCROLL_DOWN]);\n\n    if (k_state[NK_KEY_TEXT_INSERT_MODE] >= 0) nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, k_state[NK_KEY_TEXT_INSERT_MODE]);\n    if (k_state[NK_KEY_TEXT_REPLACE_MODE] >= 0) nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, k_state[NK_KEY_TEXT_REPLACE_MODE]);\n\n    nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS||\n                                    glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS);\n\n    if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||\n        glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {\n        /* Note these are physical keys and won't respect any layouts/key mapping */\n        if (k_state[NK_KEY_COPY] >= 0) nk_input_key(ctx, NK_KEY_COPY, k_state[NK_KEY_COPY]);\n        if (k_state[NK_KEY_PASTE] >= 0) nk_input_key(ctx, NK_KEY_PASTE, k_state[NK_KEY_PASTE]);\n        if (k_state[NK_KEY_CUT] >= 0) nk_input_key(ctx, NK_KEY_CUT, k_state[NK_KEY_CUT]);\n        if (k_state[NK_KEY_TEXT_UNDO] >= 0) nk_input_key(ctx, NK_KEY_TEXT_UNDO, k_state[NK_KEY_TEXT_UNDO]);\n        if (k_state[NK_KEY_TEXT_REDO] >= 0) nk_input_key(ctx, NK_KEY_TEXT_REDO, k_state[NK_KEY_TEXT_REDO]);\n        if (k_state[NK_KEY_TEXT_LINE_START] >= 0) nk_input_key(ctx, NK_KEY_TEXT_LINE_START, k_state[NK_KEY_TEXT_LINE_START]);\n        if (k_state[NK_KEY_TEXT_LINE_END] >= 0) nk_input_key(ctx, NK_KEY_TEXT_LINE_END, k_state[NK_KEY_TEXT_LINE_END]);\n        if (k_state[NK_KEY_TEXT_SELECT_ALL] >= 0) nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, k_state[NK_KEY_TEXT_SELECT_ALL]);\n        if (k_state[NK_KEY_LEFT] >= 0) nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, k_state[NK_KEY_LEFT]);\n        if (k_state[NK_KEY_RIGHT] >= 0) nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, k_state[NK_KEY_RIGHT]);\n    } else {\n        if (k_state[NK_KEY_LEFT] >= 0) nk_input_key(ctx, NK_KEY_LEFT, k_state[NK_KEY_LEFT]);\n        if (k_state[NK_KEY_RIGHT] >= 0) nk_input_key(ctx, NK_KEY_RIGHT, k_state[NK_KEY_RIGHT]);\n        nk_input_key(ctx, NK_KEY_COPY, 0);\n        nk_input_key(ctx, NK_KEY_PASTE, 0);\n        nk_input_key(ctx, NK_KEY_CUT, 0);\n    }\n\n    glfwGetCursorPos(win, &x, &y);\n    nk_input_motion(ctx, (int)x, (int)y);\n    if (ctx->input.mouse.grabbed) {\n        glfwSetCursorPos(glfw.win, (double)ctx->input.mouse.prev.x, (double)ctx->input.mouse.prev.y);\n        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n    }\n\n    nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_DOUBLE, (int)glfw.double_click_pos.x, (int)glfw.double_click_pos.y, glfw.is_double_click_down);\n    nk_input_button(ctx, NK_BUTTON_X1, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_4) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_X2, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_5) == GLFW_PRESS);\n    nk_input_scroll(ctx, glfw.scroll);\n    nk_input_end(&glfw.ctx);\n\n    /* clear after nk_input_end (-1 since we're doing up/down boolean) */\n    memset(glfw.key_events, -1, sizeof(glfw.key_events));\n\n    glfw.text_len = 0;\n    glfw.scroll = nk_vec2(0,0);\n}\n\nNK_API\nvoid nk_glfw3_shutdown(void)\n{\n    struct nk_glfw_device *dev = &glfw.ogl;\n    nk_font_atlas_clear(&glfw.atlas);\n    nk_free(&glfw.ctx);\n    glDeleteTextures(1, &dev->font_tex);\n    nk_buffer_free(&dev->cmds);\n    memset(&glfw, 0, sizeof(glfw));\n}\n\n#endif\n"
  },
  {
    "path": "demo/glfw_opengl3/Makefile",
    "content": "# Install\nBIN = demo\n\n# Flags\nCFLAGS += -g -std=c89 -Wall -Wextra -pedantic\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\nifeq ($(OS),Windows_NT)\nBIN := $(BIN).exe\nLIBS = -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32\nelse\n\tUNAME_S := $(shell uname -s)\n\tGLFW3 := $(shell pkg-config --libs glfw3)\n\tifeq ($(UNAME_S),Darwin)\n\t\tLIBS := $(GLFW3) -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -lm -lGLEW -L/usr/local/lib\n\telse\n\t\tLIBS = $(GLFW3) -lGL -lm -lGLU -lGLEW\n\tendif\nendif\n\n$(BIN):\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)\n"
  },
  {
    "path": "demo/glfw_opengl3/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <limits.h>\n#include <time.h>\n\n#include <GL/glew.h>\n#include <GLFW/glfw3.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_GLFW_GL3_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_glfw_gl3.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define MAX_VERTEX_BUFFER 512 * 1024\n#define MAX_ELEMENT_BUFFER 128 * 1024\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nstatic void error_callback(int e, const char *d)\n{printf(\"Error %d: %s\\n\", e, d);}\n\nint main(void)\n{\n    /* Platform */\n    struct nk_glfw glfw = {0};\n    static GLFWwindow *win;\n    int width = 0, height = 0;\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    /* GLFW */\n    glfwSetErrorCallback(error_callback);\n    if (!glfwInit()) {\n        fprintf(stdout, \"[GFLW] failed to init!\\n\");\n        exit(1);\n    }\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);\n    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);\n#ifdef __APPLE__\n    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);\n#endif\n    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, \"Demo\", NULL, NULL);\n    glfwMakeContextCurrent(win);\n    glfwGetWindowSize(win, &width, &height);\n\n    /* OpenGL */\n    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);\n    glewExperimental = 1;\n    if (glewInit() != GLEW_OK) {\n        fprintf(stderr, \"Failed to setup GLEW\\n\");\n        exit(1);\n    }\n\n    ctx = nk_glfw3_init(&glfw, win, NK_GLFW3_INSTALL_CALLBACKS);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {struct nk_font_atlas *atlas;\n    nk_glfw3_font_stash_begin(&glfw, &atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Roboto-Regular.ttf\", 14, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_glfw3_font_stash_end(&glfw);\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &droid->handle);*/}\n\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (!glfwWindowShouldClose(win))\n    {\n        /* Input */\n        glfwPollEvents();\n        nk_glfw3_new_frame(&glfw);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        glfwGetWindowSize(win, &width, &height);\n        glViewport(0, 0, width, height);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(bg.r, bg.g, bg.b, bg.a);\n        /* IMPORTANT: `nk_glfw_render` modifies some global OpenGL state\n         * with blending, scissor, face culling, depth test and viewport and\n         * defaults everything back into a default state.\n         * Make sure to either a.) save and restore or b.) reset your own state after\n         * rendering the UI. */\n        nk_glfw3_render(&glfw, NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);\n        glfwSwapBuffers(win);\n    }\n    nk_glfw3_shutdown(&glfw);\n    glfwTerminate();\n    return 0;\n}\n\n"
  },
  {
    "path": "demo/glfw_opengl3/nuklear_glfw_gl3.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_GLFW_GL3_H_\n#define NK_GLFW_GL3_H_\n\n#include <GLFW/glfw3.h>\n\nenum nk_glfw_init_state{\n    NK_GLFW3_DEFAULT=0,\n    NK_GLFW3_INSTALL_CALLBACKS\n};\n\n#ifndef NK_GLFW_TEXT_MAX\n#define NK_GLFW_TEXT_MAX 256\n#endif\n\nstruct nk_glfw_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint vbo, vao, ebo;\n    GLuint prog;\n    GLuint vert_shdr;\n    GLuint frag_shdr;\n    GLint attrib_pos;\n    GLint attrib_uv;\n    GLint attrib_col;\n    GLint uniform_tex;\n    GLint uniform_proj;\n    GLuint font_tex;\n};\n\nstruct nk_glfw {\n    GLFWwindow *win;\n    int width, height;\n    int display_width, display_height;\n    struct nk_glfw_device ogl;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    struct nk_vec2 fb_scale;\n    unsigned int text[NK_GLFW_TEXT_MAX];\n    nk_char key_events[NK_KEY_MAX];\n    int text_len;\n    struct nk_vec2 scroll;\n    double last_button_click;\n    int is_double_click_down;\n    struct nk_vec2 double_click_pos;\n    float delta_time_seconds_last;\n};\n\nNK_API struct nk_context*   nk_glfw3_init(struct nk_glfw* glfw, GLFWwindow *win, enum nk_glfw_init_state);\nNK_API void                 nk_glfw3_shutdown(struct nk_glfw* glfw);\nNK_API void                 nk_glfw3_font_stash_begin(struct nk_glfw* glfw, struct nk_font_atlas **atlas);\nNK_API void                 nk_glfw3_font_stash_end(struct nk_glfw* glfw);\nNK_API void                 nk_glfw3_new_frame(struct nk_glfw* glfw);\nNK_API void                 nk_glfw3_render(struct nk_glfw* glfw, enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);\n\nNK_API void                 nk_glfw3_device_destroy(struct nk_glfw* glfw);\nNK_API void                 nk_glfw3_device_create(struct nk_glfw* glfw);\n\nNK_API void                 nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);\nNK_API void                 nk_glfw3_key_callback(GLFWwindow *win, int key, int scancode, int action, int mods);\nNK_API void                 nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);\nNK_API void                 nk_glfw3_mouse_button_callback(GLFWwindow *win, int button, int action, int mods);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_GLFW_GL3_IMPLEMENTATION\n#include <string.h>\n#include <stdlib.h>\n#include <assert.h>\n\n#ifndef NK_GLFW_DOUBLE_CLICK_LO\n#define NK_GLFW_DOUBLE_CLICK_LO 0.02\n#endif\n#ifndef NK_GLFW_DOUBLE_CLICK_HI\n#define NK_GLFW_DOUBLE_CLICK_HI 0.2\n#endif\n\nstruct nk_glfw_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\n#ifdef __APPLE__\n  #define NK_SHADER_VERSION \"#version 150\\n\"\n#else\n  #define NK_SHADER_VERSION \"#version 300 es\\n\"\n#endif\n\nNK_API void\nnk_glfw3_device_create(struct nk_glfw* glfw)\n{\n    GLint status;\n    static const GLchar *vertex_shader =\n        NK_SHADER_VERSION\n        \"uniform mat4 ProjMtx;\\n\"\n        \"in vec2 Position;\\n\"\n        \"in vec2 TexCoord;\\n\"\n        \"in vec4 Color;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main() {\\n\"\n        \"   Frag_UV = TexCoord;\\n\"\n        \"   Frag_Color = Color;\\n\"\n        \"   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\\n\"\n        \"}\\n\";\n    static const GLchar *fragment_shader =\n        NK_SHADER_VERSION\n        \"precision mediump float;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"out vec4 Out_Color;\\n\"\n        \"void main(){\\n\"\n        \"   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    struct nk_glfw_device *dev = &glfw->ogl;\n    nk_buffer_init_default(&dev->cmds);\n    dev->prog = glCreateProgram();\n    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);\n    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);\n    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);\n    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);\n    glCompileShader(dev->vert_shdr);\n    glCompileShader(dev->frag_shdr);\n    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glAttachShader(dev->prog, dev->vert_shdr);\n    glAttachShader(dev->prog, dev->frag_shdr);\n    glLinkProgram(dev->prog);\n    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);\n    assert(status == GL_TRUE);\n\n    dev->uniform_tex = glGetUniformLocation(dev->prog, \"Texture\");\n    dev->uniform_proj = glGetUniformLocation(dev->prog, \"ProjMtx\");\n    dev->attrib_pos = glGetAttribLocation(dev->prog, \"Position\");\n    dev->attrib_uv = glGetAttribLocation(dev->prog, \"TexCoord\");\n    dev->attrib_col = glGetAttribLocation(dev->prog, \"Color\");\n\n    {\n        /* buffer setup */\n        GLsizei vs = sizeof(struct nk_glfw_vertex);\n        size_t vp = offsetof(struct nk_glfw_vertex, position);\n        size_t vt = offsetof(struct nk_glfw_vertex, uv);\n        size_t vc = offsetof(struct nk_glfw_vertex, col);\n\n        glGenBuffers(1, &dev->vbo);\n        glGenBuffers(1, &dev->ebo);\n        glGenVertexArrays(1, &dev->vao);\n\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glEnableVertexAttribArray((GLuint)dev->attrib_pos);\n        glEnableVertexAttribArray((GLuint)dev->attrib_uv);\n        glEnableVertexAttribArray((GLuint)dev->attrib_col);\n\n        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);\n        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);\n        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);\n    }\n\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n}\n\nNK_INTERN void\nnk_glfw3_device_upload_atlas(struct nk_glfw* glfw, const void *image, int width, int height)\n{\n    struct nk_glfw_device *dev = &glfw->ogl;\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nNK_API void\nnk_glfw3_device_destroy(struct nk_glfw* glfw)\n{\n    struct nk_glfw_device *dev = &glfw->ogl;\n    glDetachShader(dev->prog, dev->vert_shdr);\n    glDetachShader(dev->prog, dev->frag_shdr);\n    glDeleteShader(dev->vert_shdr);\n    glDeleteShader(dev->frag_shdr);\n    glDeleteProgram(dev->prog);\n    glDeleteTextures(1, &dev->font_tex);\n    glDeleteBuffers(1, &dev->vbo);\n    glDeleteBuffers(1, &dev->ebo);\n    nk_buffer_free(&dev->cmds);\n}\n\nNK_API void\nnk_glfw3_render(struct nk_glfw* glfw, enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)\n{\n    struct nk_glfw_device *dev = &glfw->ogl;\n    struct nk_buffer vbuf, ebuf;\n    GLfloat ortho[4][4] = {\n        {2.0f, 0.0f, 0.0f, 0.0f},\n        {0.0f,-2.0f, 0.0f, 0.0f},\n        {0.0f, 0.0f,-1.0f, 0.0f},\n        {-1.0f,1.0f, 0.0f, 1.0f},\n    };\n    ortho[0][0] /= (GLfloat)glfw->width;\n    ortho[1][1] /= (GLfloat)glfw->height;\n\n    /* setup global state */\n    glEnable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glActiveTexture(GL_TEXTURE0);\n\n    /* setup program */\n    glUseProgram(dev->prog);\n    glUniform1i(dev->uniform_tex, 0);\n    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);\n    glViewport(0,0,(GLsizei)glfw->display_width,(GLsizei)glfw->display_height);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        void *vertices, *elements;\n        nk_size offset = 0;\n\n        /* allocate vertex and element buffer */\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);\n\n        /* load draw vertices & elements directly into vertex + element buffer */\n        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);\n        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n                {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},\n                {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},\n                {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},\n                {NK_VERTEX_LAYOUT_END}\n            };\n            memset(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_glfw_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer);\n            nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer);\n            nk_convert(&glfw->ctx, &dev->cmds, &vbuf, &ebuf, &config);\n        }\n        glUnmapBuffer(GL_ARRAY_BUFFER);\n        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);\n\n        /* iterate over and execute each draw command */\n        nk_draw_foreach(cmd, &glfw->ctx, &dev->cmds)\n        {\n            if (!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor(\n                (GLint)(cmd->clip_rect.x * glfw->fb_scale.x),\n                (GLint)((glfw->height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw->fb_scale.y),\n                (GLint)(cmd->clip_rect.w * glfw->fb_scale.x),\n                (GLint)(cmd->clip_rect.h * glfw->fb_scale.y));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, (const void*) offset);\n            offset += cmd->elem_count * sizeof(nk_draw_index);\n        }\n        nk_clear(&glfw->ctx);\n        nk_buffer_clear(&dev->cmds);\n    }\n\n    /* default OpenGL state */\n    glUseProgram(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n    glDisable(GL_BLEND);\n    glDisable(GL_SCISSOR_TEST);\n}\n\nNK_API void\nnk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint)\n{\n    struct nk_glfw* glfw = (struct nk_glfw *)glfwGetWindowUserPointer(win);\n    if (glfw->text_len < NK_GLFW_TEXT_MAX)\n        glfw->text[glfw->text_len++] = codepoint;\n}\n\nNK_API void\nnk_glfw3_key_callback(GLFWwindow *win, int key, int scancode, int action, int mods)\n{\n    static int insert_toggle = 0;\n    struct nk_glfw* glfw = (struct nk_glfw *)glfwGetWindowUserPointer(win);\n    /*\n     * convert GLFW_REPEAT to down (technically GLFW_RELEASE, GLFW_PRESS, GLFW_REPEAT are\n     * already 0, 1, 2 but just to be clearer)\n     */\n    nk_char a = (action == GLFW_RELEASE) ? nk_false : nk_true;\n\n    NK_UNUSED(scancode);\n    NK_UNUSED(mods);\n\n    switch (key) {\n    case GLFW_KEY_DELETE:    glfw->key_events[NK_KEY_DEL] = a; break;\n    case GLFW_KEY_TAB:       glfw->key_events[NK_KEY_TAB] = a; break;\n    case GLFW_KEY_BACKSPACE: glfw->key_events[NK_KEY_BACKSPACE] = a; break;\n    case GLFW_KEY_UP:        glfw->key_events[NK_KEY_UP] = a; break;\n    case GLFW_KEY_DOWN:      glfw->key_events[NK_KEY_DOWN] = a; break;\n    case GLFW_KEY_LEFT:      glfw->key_events[NK_KEY_LEFT] = a; break;\n    case GLFW_KEY_RIGHT:     glfw->key_events[NK_KEY_RIGHT] = a; break;\n    case GLFW_KEY_ESCAPE:    glfw->key_events[NK_KEY_TEXT_RESET_MODE] = a; break;\n\n    case GLFW_KEY_PAGE_UP:   glfw->key_events[NK_KEY_SCROLL_UP] = a; break;\n    case GLFW_KEY_PAGE_DOWN: glfw->key_events[NK_KEY_SCROLL_DOWN] = a; break;\n\n    case GLFW_KEY_C:         glfw->key_events[NK_KEY_COPY] = a; break;\n    case GLFW_KEY_V:         glfw->key_events[NK_KEY_PASTE] = a; break;\n    case GLFW_KEY_X:         glfw->key_events[NK_KEY_CUT] = a; break;\n    case GLFW_KEY_Z:         glfw->key_events[NK_KEY_TEXT_UNDO] = a; break;\n    case GLFW_KEY_R:         glfw->key_events[NK_KEY_TEXT_REDO] = a; break;\n    case GLFW_KEY_B:         glfw->key_events[NK_KEY_TEXT_LINE_START] = a; break;\n    case GLFW_KEY_E:         glfw->key_events[NK_KEY_TEXT_LINE_END] = a; break;\n    case GLFW_KEY_A:         glfw->key_events[NK_KEY_TEXT_SELECT_ALL] = a; break;\n\n    case GLFW_KEY_ENTER:\n    case GLFW_KEY_KP_ENTER:\n        glfw->key_events[NK_KEY_ENTER] = a;\n        break;\n    case GLFW_KEY_INSERT:\n        /* Only switch on release to avoid repeat issues\n         * kind of confusing since we have to negate it but we're already\n         * hacking it since Nuklear treats them as two separate keys rather\n         * than a single toggle state */\n        if (!a) {\n            insert_toggle = !insert_toggle;\n            if (insert_toggle) {\n                glfw->key_events[NK_KEY_TEXT_INSERT_MODE] = !a;\n                /* glfw->key_events[NK_KEY_TEXT_REPLACE_MODE] = a; */\n            } else {\n                /* glfw->key_events[NK_KEY_TEXT_INSERT_MODE] = a; */\n                glfw->key_events[NK_KEY_TEXT_REPLACE_MODE] = !a;\n            }\n        }\n        break;\n    default:\n        ;\n    }\n}\n\nNK_API void\nnk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff)\n{\n    struct nk_glfw* glfw = (struct nk_glfw *)glfwGetWindowUserPointer(win);\n    (void)xoff;\n    glfw->scroll.x += (float)xoff;\n    glfw->scroll.y += (float)yoff;\n}\n\nNK_API void\nnk_glfw3_mouse_button_callback(GLFWwindow* win, int button, int action, int mods)\n{\n    struct nk_glfw* glfw = (struct nk_glfw *)glfwGetWindowUserPointer(win);\n    double x, y;\n    NK_UNUSED(mods);\n    if (button != GLFW_MOUSE_BUTTON_LEFT) return;\n    glfwGetCursorPos(win, &x, &y);\n    if (action == GLFW_PRESS)  {\n        double dt = glfwGetTime() - glfw->last_button_click;\n        if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) {\n            glfw->is_double_click_down = nk_true;\n            glfw->double_click_pos = nk_vec2((float)x, (float)y);\n        }\n        glfw->last_button_click = glfwGetTime();\n    } else glfw->is_double_click_down = nk_false;\n}\n\nNK_INTERN void\nnk_glfw3_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    struct nk_glfw* glfw = (struct nk_glfw*)usr.ptr;\n    const char *text = glfwGetClipboardString(glfw->win);\n    if (text) nk_textedit_paste(edit, text, nk_strlen(text));\n    (void)usr;\n}\n\nNK_INTERN void\nnk_glfw3_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    struct nk_glfw* glfw = (struct nk_glfw*)usr.ptr;\n    char *str = 0;\n    if (!len) return;\n    str = (char*)malloc((size_t)len+1);\n    if (!str) return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n    glfwSetClipboardString(glfw->win, str);\n    free(str);\n}\n\nNK_API struct nk_context*\nnk_glfw3_init(struct nk_glfw* glfw, GLFWwindow *win, enum nk_glfw_init_state init_state)\n{\n    glfwSetWindowUserPointer(win, glfw);\n    glfw->win = win;\n    if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {\n        glfwSetScrollCallback(win, nk_gflw3_scroll_callback);\n        glfwSetCharCallback(win, nk_glfw3_char_callback);\n        glfwSetKeyCallback(win, nk_glfw3_key_callback);\n        glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback);\n    }\n    nk_init_default(&glfw->ctx, 0);\n    glfw->ctx.clip.copy = nk_glfw3_clipboard_copy;\n    glfw->ctx.clip.paste = nk_glfw3_clipboard_paste;\n    glfw->ctx.clip.userdata = nk_handle_ptr(&glfw);\n    glfw->last_button_click = 0;\n    nk_glfw3_device_create(glfw);\n\n    glfw->is_double_click_down = nk_false;\n    glfw->double_click_pos = nk_vec2(0, 0);\n\n    glfw->delta_time_seconds_last = (float)glfwGetTime();\n\n    return &glfw->ctx;\n}\n\nNK_API void\nnk_glfw3_font_stash_begin(struct nk_glfw* glfw, struct nk_font_atlas **atlas)\n{\n    nk_font_atlas_init_default(&glfw->atlas);\n    nk_font_atlas_begin(&glfw->atlas);\n    *atlas = &glfw->atlas;\n}\n\nNK_API void\nnk_glfw3_font_stash_end(struct nk_glfw* glfw)\n{\n    const void *image; int w, h;\n    image = nk_font_atlas_bake(&glfw->atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_glfw3_device_upload_atlas(glfw, image, w, h);\n    nk_font_atlas_end(&glfw->atlas, nk_handle_id((int)glfw->ogl.font_tex), &glfw->ogl.tex_null);\n    if (glfw->atlas.default_font)\n        nk_style_set_font(&glfw->ctx, &glfw->atlas.default_font->handle);\n}\n\nNK_API void\nnk_glfw3_new_frame(struct nk_glfw* glfw)\n{\n    int i;\n    double x, y;\n    struct nk_context *ctx = &glfw->ctx;\n    struct GLFWwindow *win = glfw->win;\n    nk_char* k_state = glfw->key_events;\n\n    /* update the timer */\n    float delta_time_now = (float)glfwGetTime();\n    glfw->ctx.delta_time_seconds = delta_time_now - glfw->delta_time_seconds_last;\n    glfw->delta_time_seconds_last = delta_time_now;\n\n    glfwGetWindowSize(win, &glfw->width, &glfw->height);\n    glfwGetFramebufferSize(win, &glfw->display_width, &glfw->display_height);\n    glfw->fb_scale.x = (float)glfw->display_width/(float)glfw->width;\n    glfw->fb_scale.y = (float)glfw->display_height/(float)glfw->height;\n\n    nk_input_begin(ctx);\n    for (i = 0; i < glfw->text_len; ++i)\n        nk_input_unicode(ctx, glfw->text[i]);\n\n#ifdef NK_GLFW_GL3_MOUSE_GRABBING\n    /* optional grabbing behavior */\n    if (ctx->input.mouse.grab)\n        glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);\n    else if (ctx->input.mouse.ungrab)\n        glfwSetInputMode(glfw->win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);\n#endif\n\n    if (k_state[NK_KEY_DEL] >= 0) nk_input_key(ctx, NK_KEY_DEL, k_state[NK_KEY_DEL]);\n    if (k_state[NK_KEY_ENTER] >= 0) nk_input_key(ctx, NK_KEY_ENTER, k_state[NK_KEY_ENTER]);\n\n    if (k_state[NK_KEY_TEXT_RESET_MODE] >= 0) nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, k_state[NK_KEY_TEXT_RESET_MODE]);\n\n    if (k_state[NK_KEY_TAB] >= 0) nk_input_key(ctx, NK_KEY_TAB, k_state[NK_KEY_TAB]);\n    if (k_state[NK_KEY_BACKSPACE] >= 0) nk_input_key(ctx, NK_KEY_BACKSPACE, k_state[NK_KEY_BACKSPACE]);\n    if (k_state[NK_KEY_UP] >= 0) nk_input_key(ctx, NK_KEY_UP, k_state[NK_KEY_UP]);\n    if (k_state[NK_KEY_DOWN] >= 0) nk_input_key(ctx, NK_KEY_DOWN, k_state[NK_KEY_DOWN]);\n    if (k_state[NK_KEY_SCROLL_UP] >= 0) nk_input_key(ctx, NK_KEY_SCROLL_UP, k_state[NK_KEY_SCROLL_UP]);\n    if (k_state[NK_KEY_SCROLL_DOWN] >= 0) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, k_state[NK_KEY_SCROLL_DOWN]);\n\n    if (k_state[NK_KEY_TEXT_INSERT_MODE] >= 0) nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, k_state[NK_KEY_TEXT_INSERT_MODE]);\n    if (k_state[NK_KEY_TEXT_REPLACE_MODE] >= 0) nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, k_state[NK_KEY_TEXT_REPLACE_MODE]);\n\n    nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS||\n                                    glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS);\n\n    if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||\n        glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {\n        /* Note these are physical keys and won't respect any layouts/key mapping */\n        if (k_state[NK_KEY_COPY] >= 0) nk_input_key(ctx, NK_KEY_COPY, k_state[NK_KEY_COPY]);\n        if (k_state[NK_KEY_PASTE] >= 0) nk_input_key(ctx, NK_KEY_PASTE, k_state[NK_KEY_PASTE]);\n        if (k_state[NK_KEY_CUT] >= 0) nk_input_key(ctx, NK_KEY_CUT, k_state[NK_KEY_CUT]);\n        if (k_state[NK_KEY_TEXT_UNDO] >= 0) nk_input_key(ctx, NK_KEY_TEXT_UNDO, k_state[NK_KEY_TEXT_UNDO]);\n        if (k_state[NK_KEY_TEXT_REDO] >= 0) nk_input_key(ctx, NK_KEY_TEXT_REDO, k_state[NK_KEY_TEXT_REDO]);\n        if (k_state[NK_KEY_TEXT_LINE_START] >= 0) nk_input_key(ctx, NK_KEY_TEXT_LINE_START, k_state[NK_KEY_TEXT_LINE_START]);\n        if (k_state[NK_KEY_TEXT_LINE_END] >= 0) nk_input_key(ctx, NK_KEY_TEXT_LINE_END, k_state[NK_KEY_TEXT_LINE_END]);\n        if (k_state[NK_KEY_TEXT_SELECT_ALL] >= 0) nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, k_state[NK_KEY_TEXT_SELECT_ALL]);\n        if (k_state[NK_KEY_LEFT] >= 0) nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, k_state[NK_KEY_LEFT]);\n        if (k_state[NK_KEY_RIGHT] >= 0) nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, k_state[NK_KEY_RIGHT]);\n    } else {\n        if (k_state[NK_KEY_LEFT] >= 0) nk_input_key(ctx, NK_KEY_LEFT, k_state[NK_KEY_LEFT]);\n        if (k_state[NK_KEY_RIGHT] >= 0) nk_input_key(ctx, NK_KEY_RIGHT, k_state[NK_KEY_RIGHT]);\n        nk_input_key(ctx, NK_KEY_COPY, 0);\n        nk_input_key(ctx, NK_KEY_PASTE, 0);\n        nk_input_key(ctx, NK_KEY_CUT, 0);\n    }\n\n    glfwGetCursorPos(win, &x, &y);\n    nk_input_motion(ctx, (int)x, (int)y);\n#ifdef NK_GLFW_GL3_MOUSE_GRABBING\n    if (ctx->input.mouse.grabbed) {\n        glfwSetCursorPos(glfw->win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y);\n        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n    }\n#endif\n    nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_DOUBLE, (int)glfw->double_click_pos.x, (int)glfw->double_click_pos.y, glfw->is_double_click_down);\n    nk_input_button(ctx, NK_BUTTON_X1, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_4) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_X2, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_5) == GLFW_PRESS);\n    nk_input_scroll(ctx, glfw->scroll);\n    nk_input_end(&glfw->ctx);\n\n    /* clear after nk_input_end (-1 since we're doing up/down boolean) */\n    memset(glfw->key_events, -1, sizeof(glfw->key_events));\n\n    glfw->text_len = 0;\n    glfw->scroll = nk_vec2(0,0);\n}\n\nNK_API\nvoid nk_glfw3_shutdown(struct nk_glfw* glfw)\n{\n    nk_font_atlas_clear(&glfw->atlas);\n    nk_free(&glfw->ctx);\n    nk_glfw3_device_destroy(glfw);\n    memset(glfw, 0, sizeof(*glfw));\n}\n\n#endif\n"
  },
  {
    "path": "demo/glfw_opengl4/Makefile",
    "content": "# Install\nBIN = demo\n\n# Flags\nCFLAGS += -g -std=c89 -Wall -Wextra -pedantic\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\nifeq ($(OS),Windows_NT)\nBIN := $(BIN).exe\nLIBS = -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32\nelse\n\tUNAME_S := $(shell uname -s)\n\tGLFW3 := $(shell pkg-config --libs glfw3)\n\tifeq ($(UNAME_S),Darwin)\n\t\tLIBS := $(GLFW3) -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -lm -lGLEW -L/usr/local/lib\n\telse\n\t\tLIBS = $(GLFW3) -lGL -lm -lGLU -lGLEW\n\tendif\nendif\n\n$(BIN):\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)\n"
  },
  {
    "path": "demo/glfw_opengl4/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <limits.h>\n#include <time.h>\n\n#include <GL/glew.h>\n#include <GLFW/glfw3.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_GLFW_GL4_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_glfw_gl4.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define MAX_VERTEX_BUFFER 512 * 1024\n#define MAX_ELEMENT_BUFFER 128 * 1024\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nstatic void error_callback(int e, const char *d)\n{printf(\"Error %d: %s\\n\", e, d);}\n\nint main(void)\n{\n    /* Platform */\n    static GLFWwindow *win;\n    int width = 0, height = 0;\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n    struct nk_image img;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    /* GLFW */\n    glfwSetErrorCallback(error_callback);\n    if (!glfwInit()) {\n        fprintf(stdout, \"[GFLW] failed to init!\\n\");\n        exit(1);\n    }\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);\n    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);\n#ifdef __APPLE__\n    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);\n#endif\n    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, \"Demo\", NULL, NULL);\n    glfwMakeContextCurrent(win);\n    glfwGetWindowSize(win, &width, &height);\n\n    /* OpenGL */\n    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);\n    glewExperimental = 1;\n    if (glewInit() != GLEW_OK) {\n        fprintf(stderr, \"Failed to setup GLEW\\n\");\n        exit(1);\n    }\n\n    ctx = nk_glfw3_init(win, NK_GLFW3_INSTALL_CALLBACKS, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {struct nk_font_atlas *atlas;\n    nk_glfw3_font_stash_begin(&atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Roboto-Regular.ttf\", 14, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_glfw3_font_stash_end();\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &droid->handle);*/}\n\n    /* Create bindless texture.\n     * The index returned is not the opengl resource id.\n     * IF you need the GL resource id use: nk_glfw3_get_tex_ogl_id() */\n    {int tex_index = 0;\n    enum {tex_width = 256, tex_height = 256};\n    char pixels[tex_width * tex_height * 4];\n    memset(pixels, 128, sizeof(pixels));\n    tex_index = nk_glfw3_create_texture(pixels, tex_width, tex_height);\n    img = nk_image_id(tex_index);}\n\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (!glfwWindowShouldClose(win))\n    {\n        /* Input */\n        glfwPollEvents();\n        nk_glfw3_new_frame();\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* Bindless Texture */\n        if (nk_begin(ctx, \"Texture\", nk_rect(250, 150, 230, 250),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);\n            struct nk_rect total_space = nk_window_get_content_region(ctx);\n            nk_draw_image(canvas, total_space, &img, nk_white);\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        glfwGetWindowSize(win, &width, &height);\n        glViewport(0, 0, width, height);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(bg.r, bg.g, bg.b, bg.a);\n        /* IMPORTANT: `nk_glfw_render` modifies some global OpenGL state\n         * with blending, scissor, face culling, depth test and viewport and\n         * defaults everything back into a default state.\n         * Make sure to either a.) save and restore or b.) reset your own state after\n         * rendering the UI. */\n        nk_glfw3_render(NK_ANTI_ALIASING_ON);\n        glfwSwapBuffers(win);\n    }\n    nk_glfw3_shutdown();\n    glfwTerminate();\n    return 0;\n}\n\n"
  },
  {
    "path": "demo/glfw_opengl4/nuklear_glfw_gl4.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_GLFW_GL4_H_\n#define NK_GLFW_GL4_H_\n\n#include <string.h>\n#include <GLFW/glfw3.h>\n\nenum nk_glfw_init_state{\n    NK_GLFW3_DEFAULT = 0,\n    NK_GLFW3_INSTALL_CALLBACKS\n};\n\nNK_API struct nk_context*   nk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state, int max_vertex_buffer, int max_element_buffer);\nNK_API void                 nk_glfw3_shutdown(void);\nNK_API void                 nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void                 nk_glfw3_font_stash_end(void);\nNK_API void                 nk_glfw3_new_frame(void);\nNK_API void                 nk_glfw3_render(enum nk_anti_aliasing);\n\nNK_API void                 nk_glfw3_device_destroy(void);\nNK_API void                 nk_glfw3_device_create(void);\n\nNK_API void                 nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);\nNK_API void                 nk_glfw3_key_callback(GLFWwindow *win, int key, int scancode, int action, int mods);\nNK_API void                 nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);\nNK_API void                 nk_glfw3_mouse_button_callback(GLFWwindow *win, int button, int action, int mods);\n\nNK_API unsigned int                  nk_glfw3_create_texture(const void* image, int width, int height);\nNK_API void                 nk_glfw3_destroy_texture(unsigned int tex_index);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_GLFW_GL4_IMPLEMENTATION\n#undef NK_GLFW_GL4_IMPLEMENTATION\n#include <stdio.h>\n#include <stdlib.h>\n#include <assert.h>\n\n#ifndef NK_GLFW_TEXT_MAX\n#define NK_GLFW_TEXT_MAX 256\n#endif\n#ifndef NK_GLFW_DOUBLE_CLICK_LO\n#define NK_GLFW_DOUBLE_CLICK_LO 0.02\n#endif\n#ifndef NK_GLFW_DOUBLE_CLICK_HI\n#define NK_GLFW_DOUBLE_CLICK_HI 0.2\n#endif\n\nstruct nk_glfw_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstruct nk_glfw_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint vbo, vao, ebo;\n    GLuint prog;\n    GLuint vert_shdr;\n    GLuint frag_shdr;\n    GLint attrib_pos;\n    GLint attrib_uv;\n    GLint attrib_col;\n    GLint uniform_tex;\n    GLint uniform_proj;\n    int font_tex_index;\n    int max_vertex_buffer;\n    int max_element_buffer;\n    struct nk_glfw_vertex *vert_buffer;\n    int *elem_buffer;\n    GLsync buffer_sync;\n};\n\nstatic struct nk_glfw {\n    GLFWwindow *win;\n    int width, height;\n    int display_width, display_height;\n    struct nk_glfw_device ogl;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    struct nk_vec2 fb_scale;\n    unsigned int text[NK_GLFW_TEXT_MAX];\n    nk_char key_events[NK_KEY_MAX];\n    int text_len;\n    struct nk_vec2 scroll;\n    double last_button_click;\n    int is_double_click_down;\n    struct nk_vec2 double_click_pos;\n    float delta_time_seconds_last;\n} glfw;\n\n#define NK_SHADER_VERSION \"#version 450 core\\n\"\n#define NK_SHADER_BINDLESS \"#extension GL_ARB_bindless_texture : require\\n\"\n\nNK_API void\nnk_glfw3_device_create()\n{\n    GLint status;\n    GLint len = 0;\n    static const GLchar *vertex_shader =\n        NK_SHADER_VERSION\n        NK_SHADER_BINDLESS\n        \"uniform mat4 ProjMtx;\\n\"\n        \"in vec2 Position;\\n\"\n        \"in vec2 TexCoord;\\n\"\n        \"in vec4 Color;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main() {\\n\"\n        \"   Frag_UV = TexCoord;\\n\"\n        \"   Frag_Color = Color;\\n\"\n        \"   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\\n\"\n        \"}\\n\";\n    static const GLchar *fragment_shader =\n        NK_SHADER_VERSION\n        NK_SHADER_BINDLESS\n        \"precision mediump float;\\n\"\n        \"layout(bindless_sampler) uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"out vec4 Out_Color;\\n\"\n        \"void main(){\\n\"\n        \"   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    struct nk_glfw_device *dev = &glfw.ogl;\n    nk_buffer_init_default(&dev->cmds);\n    dev->prog = glCreateProgram();\n    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);\n    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);\n\n    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);\n    glCompileShader(dev->vert_shdr);\n    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);\n    glGetShaderiv(dev->vert_shdr, GL_INFO_LOG_LENGTH, &len);\n    if (len > 1) {\n        char *log = (char*)calloc((size_t)len, sizeof(char));\n        glGetShaderInfoLog(dev->vert_shdr, len, NULL, log);\n        fprintf(stdout, \"[GL]: failed to compile shader: %s\", log);\n        free(log);\n    }\n    assert(status == GL_TRUE);\n\n    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);\n    glCompileShader(dev->frag_shdr);\n    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);\n    glGetShaderiv(dev->frag_shdr, GL_INFO_LOG_LENGTH, &len);\n    if (len > 1) {\n        char *log = (char*)calloc((size_t)len, sizeof(char));\n        glGetShaderInfoLog(dev->frag_shdr, len, NULL, log);\n        fprintf(stdout, \"[GL]: failed to compile shader: %s\", log);\n        free(log);\n    }\n    assert(status == GL_TRUE);\n\n    glAttachShader(dev->prog, dev->vert_shdr);\n    glAttachShader(dev->prog, dev->frag_shdr);\n    glLinkProgram(dev->prog);\n    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);\n    assert(status == GL_TRUE);\n\n    dev->uniform_tex = glGetUniformLocation(dev->prog, \"Texture\");\n    dev->uniform_proj = glGetUniformLocation(dev->prog, \"ProjMtx\");\n    dev->attrib_pos = glGetAttribLocation(dev->prog, \"Position\");\n    dev->attrib_uv = glGetAttribLocation(dev->prog, \"TexCoord\");\n    dev->attrib_col = glGetAttribLocation(dev->prog, \"Color\");\n\n    {\n        /* buffer setup */\n        GLsizei vs = sizeof(struct nk_glfw_vertex);\n        size_t vp = offsetof(struct nk_glfw_vertex, position);\n        size_t vt = offsetof(struct nk_glfw_vertex, uv);\n        size_t vc = offsetof(struct nk_glfw_vertex, col);\n\n        GLuint pos = (GLuint)dev->attrib_pos;\n        GLuint uv = (GLuint)dev->attrib_uv;\n        GLuint col = (GLuint)dev->attrib_col;\n\n        glCreateVertexArrays(1, &dev->vao);\n        glCreateBuffers(1, &dev->vbo);\n        glCreateBuffers(1, &dev->ebo);\n\n        glEnableVertexArrayAttrib(dev->vao, pos);\n        glEnableVertexArrayAttrib(dev->vao, uv);\n        glEnableVertexArrayAttrib(dev->vao, col);\n\n        glVertexArrayAttribBinding(dev->vao, pos, 0);\n        glVertexArrayAttribBinding(dev->vao, uv, 0);\n        glVertexArrayAttribBinding(dev->vao, col, 0);\n\n        glVertexArrayAttribFormat(dev->vao, pos, 2, GL_FLOAT, GL_FALSE, vp);\n        glVertexArrayAttribFormat(dev->vao, uv, 2, GL_FLOAT, GL_FALSE, vt);\n        glVertexArrayAttribFormat(dev->vao, col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vc);\n\n        glVertexArrayElementBuffer(dev->vao, dev->ebo);\n        glVertexArrayVertexBuffer(dev->vao, 0, dev->vbo, 0, vs);\n    }\n\n    /* Persistent mapped buffers */\n    {GLsizei vb_size = dev->max_vertex_buffer;\n    GLsizei eb_size = dev->max_element_buffer;\n    GLbitfield flags = GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT;\n    glNamedBufferStorage(dev->vbo, vb_size, 0, flags);\n    glNamedBufferStorage(dev->ebo, eb_size, 0, flags);\n    dev->vert_buffer = (struct nk_glfw_vertex*) glMapNamedBufferRange(dev->vbo, 0, vb_size, flags);\n    dev->elem_buffer = (int*) glMapNamedBufferRange(dev->ebo, 0, eb_size, flags);}\n\n}\n\nNK_API unsigned int\nnk_glfw3_create_texture(const void* image, int width, int height)\n{\n    GLuint id;\n    GLsizei w = (GLsizei)width;\n    GLsizei h = (GLsizei)height;\n\n    glCreateTextures(GL_TEXTURE_2D, 1, &id);\n\n    glTextureParameteri(id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTextureParameteri(id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTextureParameteri(id, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTextureParameteri(id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTextureStorage2D(id, 1, GL_RGBA8, w, h);\n    if (image)\n        glTextureSubImage2D(id, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, image);\n    else glClearTexImage(id, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);\n\n    {GLuint64 handle = glGetTextureHandleARB(id);\n    glMakeTextureHandleResidentARB(handle);}\n    return id;\n}\n\nNK_API void\nnk_glfw3_destroy_texture(unsigned int id)\n{\n    glMakeTextureHandleNonResidentARB(glGetTextureHandleARB(id));\n    glDeleteTextures(1, &id);\n}\n\nNK_INTERN void\nnk_glfw3_device_upload_atlas(const void *image, int width, int height)\n{\n    struct nk_glfw_device *dev = &glfw.ogl;\n    dev->font_tex_index = nk_glfw3_create_texture(image, width, height);\n}\n\nNK_API void\nnk_glfw3_device_destroy(void)\n{\n    struct nk_glfw_device *dev = &glfw.ogl;\n    glDetachShader(dev->prog, dev->vert_shdr);\n    glDetachShader(dev->prog, dev->frag_shdr);\n    glDeleteShader(dev->vert_shdr);\n    glDeleteShader(dev->frag_shdr);\n    glDeleteProgram(dev->prog);\n    nk_glfw3_destroy_texture(dev->font_tex_index);\n\n    glUnmapNamedBuffer(dev->vbo);\n    glUnmapNamedBuffer(dev->ebo);\n    glDeleteBuffers(1, &dev->vbo);\n    glDeleteBuffers(1, &dev->ebo);\n    glDeleteVertexArrays(1, &dev->vao);\n    nk_buffer_free(&dev->cmds);\n}\n\nNK_INTERN void\nnk_glfw3_wait_for_buffer_unlock()\n{\n    struct nk_glfw_device *dev = &glfw.ogl;\n    if(!dev->buffer_sync)\n        return;\n\n    while (1) {\n        GLenum wait = glClientWaitSync(dev->buffer_sync, GL_SYNC_FLUSH_COMMANDS_BIT, 1);\n        if (wait == GL_ALREADY_SIGNALED || wait == GL_CONDITION_SATISFIED)\n            return;\n    }\n}\n\nNK_INTERN void\nnk_glfw3_lock_buffer()\n{\n    struct nk_glfw_device *dev = &glfw.ogl;\n    if(dev->buffer_sync) glDeleteSync(dev->buffer_sync);\n    dev->buffer_sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);\n}\n\nNK_API void\nnk_glfw3_render(enum nk_anti_aliasing AA)\n{\n    struct nk_glfw_device *dev = &glfw.ogl;\n    struct nk_buffer vbuf, ebuf;\n    GLfloat ortho[4][4] = {\n        {2.0f, 0.0f, 0.0f, 0.0f},\n        {0.0f,-2.0f, 0.0f, 0.0f},\n        {0.0f, 0.0f,-1.0f, 0.0f},\n        {-1.0f,1.0f, 0.0f, 1.0f},\n    };\n    ortho[0][0] /= (GLfloat)glfw.width;\n    ortho[1][1] /= (GLfloat)glfw.height;\n\n    /* setup global state */\n    glEnable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n\n    /* setup program */\n    glUseProgram(dev->prog);\n    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);\n    glViewport(0,0,(GLsizei)glfw.display_width,(GLsizei)glfw.display_height);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        void *vertices, *elements;\n        const nk_draw_index *offset = NULL;\n\n        glBindVertexArray(dev->vao);\n\n        /* load draw vertices & elements directly into vertex + element buffer */\n        vertices = dev->vert_buffer;\n        elements = dev->elem_buffer;\n        {\n            /* Wait until GPU is done with buffer */\n            nk_glfw3_wait_for_buffer_unlock();\n            {\n                /* fill convert configuration */\n                struct nk_convert_config config;\n                static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n                    {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},\n                    {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},\n                    {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},\n                    {NK_VERTEX_LAYOUT_END}\n                };\n                memset(&config, 0, sizeof(config));\n                config.vertex_layout = vertex_layout;\n                config.vertex_size = sizeof(struct nk_glfw_vertex);\n                config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);\n                config.tex_null = dev->tex_null;\n                config.circle_segment_count = 22;\n                config.curve_segment_count = 22;\n                config.arc_segment_count = 22;\n                config.global_alpha = 1.0f;\n                config.shape_AA = AA;\n                config.line_AA = AA;\n\n                /* setup buffers to load vertices and elements */\n                nk_buffer_init_fixed(&vbuf, vertices, (size_t)dev->max_vertex_buffer);\n                nk_buffer_init_fixed(&ebuf, elements, (size_t)dev->max_element_buffer);\n                nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n            }\n        }\n\n        /* iterate over and execute each draw command */\n        nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds)\n        {\n            GLuint64 tex_handle;\n            if (!cmd->elem_count) continue;\n\n            tex_handle = glGetTextureHandleARB((unsigned int)cmd->texture.id);\n\n            /* tex handle must be made resident in each context that uses it */\n            if (!glIsTextureHandleResidentARB(tex_handle))\n                glMakeTextureHandleResidentARB(tex_handle);\n\n            glUniformHandleui64ARB(dev->uniform_tex, tex_handle);\n            glScissor(\n                (GLint)(cmd->clip_rect.x * glfw.fb_scale.x),\n                (GLint)((glfw.height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * glfw.fb_scale.y),\n                (GLint)(cmd->clip_rect.w * glfw.fb_scale.x),\n                (GLint)(cmd->clip_rect.h * glfw.fb_scale.y));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(&glfw.ctx);\n        nk_buffer_clear(&dev->cmds);\n    }\n    /* default OpenGL state */\n    glUseProgram(0);\n    glBindVertexArray(0);\n    glDisable(GL_BLEND);\n    glDisable(GL_SCISSOR_TEST);\n    /* Lock buffer until GPU has finished draw command */\n    nk_glfw3_lock_buffer();\n}\n\nNK_API void\nnk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint)\n{\n    (void)win;\n    if (glfw.text_len < NK_GLFW_TEXT_MAX)\n        glfw.text[glfw.text_len++] = codepoint;\n}\n\nNK_API void\nnk_glfw3_key_callback(GLFWwindow *win, int key, int scancode, int action, int mods)\n{\n    static int insert_toggle = 0;\n    /*\n     * convert GLFW_REPEAT to down (technically GLFW_RELEASE, GLFW_PRESS, GLFW_REPEAT are\n     * already 0, 1, 2 but just to be clearer)\n     */\n    nk_char a = (action == GLFW_RELEASE) ? nk_false : nk_true;\n\n    NK_UNUSED(win);\n    NK_UNUSED(scancode);\n    NK_UNUSED(mods);\n\n    switch (key) {\n    case GLFW_KEY_DELETE:    glfw.key_events[NK_KEY_DEL] = a; break;\n    case GLFW_KEY_TAB:       glfw.key_events[NK_KEY_TAB] = a; break;\n    case GLFW_KEY_BACKSPACE: glfw.key_events[NK_KEY_BACKSPACE] = a; break;\n    case GLFW_KEY_UP:        glfw.key_events[NK_KEY_UP] = a; break;\n    case GLFW_KEY_DOWN:      glfw.key_events[NK_KEY_DOWN] = a; break;\n    case GLFW_KEY_LEFT:      glfw.key_events[NK_KEY_LEFT] = a; break;\n    case GLFW_KEY_RIGHT:     glfw.key_events[NK_KEY_RIGHT] = a; break;\n    case GLFW_KEY_ESCAPE:    glfw.key_events[NK_KEY_TEXT_RESET_MODE] = a; break;\n\n    case GLFW_KEY_PAGE_UP:   glfw.key_events[NK_KEY_SCROLL_UP] = a; break;\n    case GLFW_KEY_PAGE_DOWN: glfw.key_events[NK_KEY_SCROLL_DOWN] = a; break;\n\n    /* have to add all keys used for nuklear to get correct repeat behavior\n     * NOTE these are scancodes so your custom layout won't matter unfortunately\n     * Also while including everything will prevent unnecessary input calls,\n     * only the ones with visible effects really matter, ie paste, undo, redo\n     * selecting all, copying or cutting 40 times before you release the keys\n     * doesn't actually cause any visible problems */\n\n    case GLFW_KEY_C:         glfw.key_events[NK_KEY_COPY] = a; break;\n    case GLFW_KEY_V:         glfw.key_events[NK_KEY_PASTE] = a; break;\n    case GLFW_KEY_X:         glfw.key_events[NK_KEY_CUT] = a; break;\n    case GLFW_KEY_Z:         glfw.key_events[NK_KEY_TEXT_UNDO] = a; break;\n    case GLFW_KEY_R:         glfw.key_events[NK_KEY_TEXT_REDO] = a; break;\n    case GLFW_KEY_B:         glfw.key_events[NK_KEY_TEXT_LINE_START] = a; break;\n    case GLFW_KEY_E:         glfw.key_events[NK_KEY_TEXT_LINE_END] = a; break;\n    case GLFW_KEY_A:         glfw.key_events[NK_KEY_TEXT_SELECT_ALL] = a; break;\n\n    case GLFW_KEY_ENTER:\n    case GLFW_KEY_KP_ENTER:\n        glfw.key_events[NK_KEY_ENTER] = a;\n        break;\n    case GLFW_KEY_INSERT:\n        /* Only switch on release to avoid repeat issues\n         * kind of confusing since we have to negate it but we're already\n         * hacking it since Nuklear treats them as two separate keys rather\n         * than a single toggle state */\n        if (!a) {\n            insert_toggle = !insert_toggle;\n            if (insert_toggle) {\n                glfw.key_events[NK_KEY_TEXT_INSERT_MODE] = !a;\n                /* glfw.key_events[NK_KEY_TEXT_REPLACE_MODE] = a; */\n            } else {\n                /* glfw.key_events[NK_KEY_TEXT_INSERT_MODE] = a; */\n                glfw.key_events[NK_KEY_TEXT_REPLACE_MODE] = !a;\n            }\n        }\n        break;\n    default:\n        ;\n    }\n}\n\nNK_API void\nnk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff)\n{\n    (void)win; (void)xoff;\n    glfw.scroll.x += (float)xoff;\n    glfw.scroll.y += (float)yoff;\n}\n\nNK_API void\nnk_glfw3_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)\n{\n    double x, y;\n    NK_UNUSED(mods);\n    if (button != GLFW_MOUSE_BUTTON_LEFT) return;\n    glfwGetCursorPos(window, &x, &y);\n    if (action == GLFW_PRESS)  {\n        double dt = glfwGetTime() - glfw.last_button_click;\n        if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) {\n            glfw.is_double_click_down = nk_true;\n            glfw.double_click_pos = nk_vec2((float)x, (float)y);\n        }\n        glfw.last_button_click = glfwGetTime();\n    } else glfw.is_double_click_down = nk_false;\n}\n\nNK_INTERN void\nnk_glfw3_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    const char *text = glfwGetClipboardString(glfw.win);\n    if (text) nk_textedit_paste(edit, text, nk_strlen(text));\n    (void)usr;\n}\n\nNK_INTERN void\nnk_glfw3_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    char *str = 0;\n    (void)usr;\n    if (!len) return;\n    str = (char*)malloc((size_t)len+1);\n    if (!str) return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n    glfwSetClipboardString(glfw.win, str);\n    free(str);\n}\n\nNK_API struct nk_context*\nnk_glfw3_init(GLFWwindow *win, enum nk_glfw_init_state init_state,\n              int max_vertex_buffer, int max_element_buffer)\n{\n    glfw.win = win;\n    if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {\n        glfwSetScrollCallback(win, nk_gflw3_scroll_callback);\n        glfwSetCharCallback(win, nk_glfw3_char_callback);\n        glfwSetKeyCallback(win, nk_glfw3_key_callback);\n        glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback);\n    }\n    nk_init_default(&glfw.ctx, 0);\n    glfw.ctx.clip.copy = nk_glfw3_clipboard_copy;\n    glfw.ctx.clip.paste = nk_glfw3_clipboard_paste;\n    glfw.ctx.clip.userdata = nk_handle_ptr(0);\n    glfw.last_button_click = 0;\n\n    {struct nk_glfw_device *dev = &glfw.ogl;\n    dev->max_vertex_buffer = max_vertex_buffer;\n    dev->max_element_buffer = max_element_buffer;\n    nk_glfw3_device_create();}\n\n    glfw.is_double_click_down = nk_false;\n    glfw.double_click_pos = nk_vec2(0, 0);\n\n    glfw.delta_time_seconds_last = (float)glfwGetTime();\n\n    return &glfw.ctx;\n}\n\nNK_API void\nnk_glfw3_font_stash_begin(struct nk_font_atlas **atlas)\n{\n    nk_font_atlas_init_default(&glfw.atlas);\n    nk_font_atlas_begin(&glfw.atlas);\n    *atlas = &glfw.atlas;\n}\n\nNK_API void\nnk_glfw3_font_stash_end(void)\n{\n    const void *image; int w, h;\n    image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_glfw3_device_upload_atlas(image, w, h);\n    nk_font_atlas_end(&glfw.atlas, nk_handle_id((int)glfw.ogl.font_tex_index), &glfw.ogl.tex_null);\n    if (glfw.atlas.default_font)\n        nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle);\n}\n\nNK_API void\nnk_glfw3_new_frame(void)\n{\n    int i;\n    double x, y;\n    struct nk_context *ctx = &glfw.ctx;\n    struct GLFWwindow *win = glfw.win;\n    nk_char* k_state = glfw.key_events;\n\n    /* update the timer */\n    float delta_time_now = (float)glfwGetTime();\n    glfw.ctx.delta_time_seconds = delta_time_now - glfw.delta_time_seconds_last;\n    glfw.delta_time_seconds_last = delta_time_now;\n\n    glfwGetWindowSize(win, &glfw.width, &glfw.height);\n    glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height);\n    glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width;\n    glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height;\n\n    nk_input_begin(ctx);\n    for (i = 0; i < glfw.text_len; ++i)\n        nk_input_unicode(ctx, glfw.text[i]);\n\n#ifdef NK_GLFW_GL4_MOUSE_GRABBING\n    /* optional grabbing behavior */\n    if (ctx->input.mouse.grab)\n        glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);\n    else if (ctx->input.mouse.ungrab)\n        glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);\n#endif\n\n    if (k_state[NK_KEY_DEL] >= 0) nk_input_key(ctx, NK_KEY_DEL, k_state[NK_KEY_DEL]);\n    if (k_state[NK_KEY_ENTER] >= 0) nk_input_key(ctx, NK_KEY_ENTER, k_state[NK_KEY_ENTER]);\n\n    if (k_state[NK_KEY_TEXT_RESET_MODE] >= 0) nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, k_state[NK_KEY_TEXT_RESET_MODE]);\n\n    if (k_state[NK_KEY_TAB] >= 0) nk_input_key(ctx, NK_KEY_TAB, k_state[NK_KEY_TAB]);\n    if (k_state[NK_KEY_BACKSPACE] >= 0) nk_input_key(ctx, NK_KEY_BACKSPACE, k_state[NK_KEY_BACKSPACE]);\n    if (k_state[NK_KEY_UP] >= 0) nk_input_key(ctx, NK_KEY_UP, k_state[NK_KEY_UP]);\n    if (k_state[NK_KEY_DOWN] >= 0) nk_input_key(ctx, NK_KEY_DOWN, k_state[NK_KEY_DOWN]);\n    if (k_state[NK_KEY_SCROLL_UP] >= 0) nk_input_key(ctx, NK_KEY_SCROLL_UP, k_state[NK_KEY_SCROLL_UP]);\n    if (k_state[NK_KEY_SCROLL_DOWN] >= 0) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, k_state[NK_KEY_SCROLL_DOWN]);\n\n    if (k_state[NK_KEY_TEXT_INSERT_MODE] >= 0) nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, k_state[NK_KEY_TEXT_INSERT_MODE]);\n    if (k_state[NK_KEY_TEXT_REPLACE_MODE] >= 0) nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, k_state[NK_KEY_TEXT_REPLACE_MODE]);\n\n    nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS||\n                                    glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS);\n\n    if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||\n        glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {\n        /* Note these are physical keys and won't respect any layouts/key mapping */\n        if (k_state[NK_KEY_COPY] >= 0) nk_input_key(ctx, NK_KEY_COPY, k_state[NK_KEY_COPY]);\n        if (k_state[NK_KEY_PASTE] >= 0) nk_input_key(ctx, NK_KEY_PASTE, k_state[NK_KEY_PASTE]);\n        if (k_state[NK_KEY_CUT] >= 0) nk_input_key(ctx, NK_KEY_CUT, k_state[NK_KEY_CUT]);\n        if (k_state[NK_KEY_TEXT_UNDO] >= 0) nk_input_key(ctx, NK_KEY_TEXT_UNDO, k_state[NK_KEY_TEXT_UNDO]);\n        if (k_state[NK_KEY_TEXT_REDO] >= 0) nk_input_key(ctx, NK_KEY_TEXT_REDO, k_state[NK_KEY_TEXT_REDO]);\n        if (k_state[NK_KEY_TEXT_LINE_START] >= 0) nk_input_key(ctx, NK_KEY_TEXT_LINE_START, k_state[NK_KEY_TEXT_LINE_START]);\n        if (k_state[NK_KEY_TEXT_LINE_END] >= 0) nk_input_key(ctx, NK_KEY_TEXT_LINE_END, k_state[NK_KEY_TEXT_LINE_END]);\n        if (k_state[NK_KEY_TEXT_SELECT_ALL] >= 0) nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, k_state[NK_KEY_TEXT_SELECT_ALL]);\n        if (k_state[NK_KEY_LEFT] >= 0) nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, k_state[NK_KEY_LEFT]);\n        if (k_state[NK_KEY_RIGHT] >= 0) nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, k_state[NK_KEY_RIGHT]);\n    } else {\n        if (k_state[NK_KEY_LEFT] >= 0) nk_input_key(ctx, NK_KEY_LEFT, k_state[NK_KEY_LEFT]);\n        if (k_state[NK_KEY_RIGHT] >= 0) nk_input_key(ctx, NK_KEY_RIGHT, k_state[NK_KEY_RIGHT]);\n        nk_input_key(ctx, NK_KEY_COPY, 0);\n        nk_input_key(ctx, NK_KEY_PASTE, 0);\n        nk_input_key(ctx, NK_KEY_CUT, 0);\n    }\n\n    glfwGetCursorPos(win, &x, &y);\n    nk_input_motion(ctx, (int)x, (int)y);\n#ifdef NK_GLFW_GL4_MOUSE_GRABBING\n    if (ctx->input.mouse.grabbed) {\n        glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x, ctx->input.mouse.prev.y);\n        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n    }\n#endif\n    nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_DOUBLE, (int)glfw.double_click_pos.x, (int)glfw.double_click_pos.y, glfw.is_double_click_down);\n    nk_input_button(ctx, NK_BUTTON_X1, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_4) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_X2, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_5) == GLFW_PRESS);\n    nk_input_scroll(ctx, glfw.scroll);\n    nk_input_end(&glfw.ctx);\n\n    /* clear after nk_input_end (-1 since we're doing up/down boolean) */\n    memset(glfw.key_events, -1, sizeof(glfw.key_events));\n\n    glfw.text_len = 0;\n    glfw.scroll = nk_vec2(0,0);\n}\n\nNK_API\nvoid nk_glfw3_shutdown(void)\n{\n    nk_font_atlas_clear(&glfw.atlas);\n    nk_free(&glfw.ctx);\n    nk_glfw3_device_destroy();\n    memset(&glfw, 0, sizeof(glfw));\n}\n\n#endif\n"
  },
  {
    "path": "demo/glfw_vulkan/.clang-format",
    "content": "---\nBasedOnStyle: LLVM\n# same as .editorconfig\nIndentWidth: 4\n"
  },
  {
    "path": "demo/glfw_vulkan/.gitignore",
    "content": "src/nuklearshaders/*.spv\nsrc/nuklear_glfw_vulkan.h\nshaders/*.spv\n"
  },
  {
    "path": "demo/glfw_vulkan/Makefile",
    "content": "# Install\nBIN = demo\n\n# Flags\nCFLAGS += -std=c89 -Wall -Wextra -pedantic\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\nifeq ($(OS),Windows_NT)\nBIN := $(BIN).exe\nLIBS = -lglfw3 -lvulkan -lm\nelse\n\tUNAME_S := $(shell uname -s)\n\tGLFW3 := $(shell pkg-config --libs glfw3)\n    LIBS = $(GLFW3) -lvulkan -lm\nendif\n\n\n$(BIN): shaders/demo.vert.spv shaders/demo.frag.spv\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)\n\nshaders/demo.vert.spv: shaders/demo.vert\n\tglslc --target-env=vulkan shaders/demo.vert -o shaders/demo.vert.spv\n\nshaders/demo.frag.spv: shaders/demo.frag\n\tglslc --target-env=vulkan shaders/demo.frag -o shaders/demo.frag.spv\n"
  },
  {
    "path": "demo/glfw_vulkan/README.md",
    "content": "# nuklear glfw vulkan\n\n## Theory of operation\n\nThe nuklear glfw vulkan integration creates an independent graphics pipeline that will render the nuklear UI to separate render targets.\nThe application is responsible to fully manage these render targets. So it must ensure they are properly sized (and resized when requested).\n\nFurthermore it is assumed that you will have a swap chain in place and the number of nuklear overlay images and number of swap chain images match.\n\nThis is how you can integrate it in your application:\n\n```\n/*\nSetup: overlay_images have been created and their number match with the number\nof the swap_chain_images of your application. The overlay_images in this\nexample have the same format as your swap_chain images (optional)\n*/\n    struct nk_context *ctx = nk_glfw3_init(\n        demo.win, demo.device, demo.physical_device, demo.indices.graphics,\n        demo.overlay_image_views, demo.swap_chain_images_len,\n        demo.swap_chain_image_format, NK_GLFW3_INSTALL_CALLBACKS,\n        MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);\n[...]\n/*\nin your draw loop draw you can then render to the overlay image at\n`image_index`\nyour own application can then wait for the semaphore and produce\nthe swap_chain_image at `image_index`\nthis should simply sample from the overlay_image (see example)\n*/\nnk_semaphore semaphore =\n    nk_glfw3_render(demo.graphics_queue, image_index,\n                    demo.image_available, NK_ANTI_ALIASING_ON);\n    if (!render(&demo, &bg, nk_semaphore, image_index)) {\n        fprintf(stderr, \"render failed\\n\");\n        return false;\n    }\n```\n\nYou must call `nk_glfw3_resize` whenever the size of the overlay_images resize.\n\n## Using images\n\nImages can be used by providing a VkImageView as an nk_image_ptr to nuklear:\n\n```\nimg = nk_image_ptr(demo.demo_texture_image_view);\n```\n\nNote that they must have SHADER_READ_OPTIMAL layout\n\nIt is currently not possible to specify how they are being sampled. The nuklear glfw vulkan integration uses a fixed sampler that does linear filtering.\n"
  },
  {
    "path": "demo/glfw_vulkan/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n#include <limits.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <time.h>\n\n#define GLFW_INCLUDE_VULKAN\n#include <GLFW/glfw3.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_GLFW_VULKAN_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_glfw_vulkan.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define MAX_VERTEX_BUFFER 512 * 1024\n#define MAX_ELEMENT_BUFFER 128 * 1024\n#define MAX_IN_FLIGHT_FRAMES 2\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n#define INCLUDE_STYLE\n#define INCLUDE_CALCULATOR\n#define INCLUDE_CANVAS\n#define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n#define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n#include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n#include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n#include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n#include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n#include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n#include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\n\nstatic const char *validation_layer_name = \"VK_LAYER_KHRONOS_validation\";\n\nstruct queue_family_indices {\n    int graphics;\n    int present;\n};\n\nstruct swap_chain_support_details {\n    VkSurfaceCapabilitiesKHR capabilities;\n    VkSurfaceFormatKHR *formats;\n    uint32_t formats_len;\n    VkPresentModeKHR *present_modes;\n    uint32_t present_modes_len;\n};\n\nvoid swap_chain_support_details_free(\n    struct swap_chain_support_details *swap_chain_support) {\n    if (swap_chain_support->formats_len > 0) {\n        free(swap_chain_support->formats);\n        swap_chain_support->formats = NULL;\n    }\n    if (swap_chain_support->present_modes_len > 0) {\n        free(swap_chain_support->present_modes);\n        swap_chain_support->present_modes = NULL;\n    }\n}\n\nstruct vulkan_demo {\n    GLFWwindow *win;\n    VkInstance instance;\n    VkDebugUtilsMessengerEXT debug_messenger;\n    VkSurfaceKHR surface;\n    VkPhysicalDevice physical_device;\n    struct queue_family_indices indices;\n    VkDevice device;\n    VkQueue graphics_queue;\n    VkQueue present_queue;\n    VkSampler sampler;\n\n    VkSwapchainKHR swap_chain;\n    VkImage *swap_chain_images;\n    uint32_t swap_chain_images_len;\n    VkImageView *swap_chain_image_views;\n    VkFormat swap_chain_image_format;\n    VkExtent2D swap_chain_image_extent;\n\n    VkImage *overlay_images;\n    VkImageView *overlay_image_views;\n    VkDeviceMemory *overlay_image_memories;\n\n    VkRenderPass render_pass;\n    VkFramebuffer *framebuffers;\n    VkDescriptorSetLayout descriptor_set_layout;\n    VkDescriptorPool descriptor_pool;\n    VkDescriptorSet *descriptor_sets;\n    VkPipelineLayout pipeline_layout;\n    VkPipeline pipeline;\n    VkCommandPool command_pool;\n    VkCommandBuffer *command_buffers;\n    VkSemaphore *image_available;\n    VkSemaphore *render_finished;\n\n    VkImage demo_texture_image;\n    VkImageView demo_texture_image_view;\n    VkDeviceMemory demo_texture_memory;\n\n    VkFence *render_fence;\n    uint32_t current_in_flight_frame;\n\n    bool framebuffer_resized;\n};\n\nstatic void glfw_framebuffer_resize_callback(GLFWwindow* window, int width, int height) {\n    struct vulkan_demo* demo;\n\n    (void)width;\n    (void)height;\n    demo = glfwGetWindowUserPointer(window);\n    demo->framebuffer_resized = true;\n}\n\nstatic void glfw_error_callback(int e, const char *d) {\n    fprintf(stderr, \"Error %d: %s\\n\", e, d);\n}\n\nVKAPI_ATTR VkBool32 VKAPI_CALL\nvulkan_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,\n                      VkDebugUtilsMessageTypeFlagsEXT message_type,\n                      const VkDebugUtilsMessengerCallbackDataEXT *callback_data,\n                      void *user_data) {\n    (void)message_severity;\n    (void)message_type;\n    (void)user_data;\n    fprintf(stderr, \"validation layer: %s\\n\", callback_data->pMessage);\n\n    return VK_FALSE;\n}\n\nbool check_validation_layer_support() {\n    uint32_t layer_count;\n    bool ret = false;\n    VkResult result;\n    uint32_t i;\n    VkLayerProperties *available_layers = NULL;\n\n    result = vkEnumerateInstanceLayerProperties(&layer_count, NULL);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumerateInstanceLayerProperties failed: %d\\n\",\n                result);\n        return ret;\n    }\n\n    available_layers = malloc(layer_count * sizeof(VkLayerProperties));\n    result = vkEnumerateInstanceLayerProperties(&layer_count, available_layers);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumerateInstanceLayerProperties failed: %d\\n\",\n                result);\n        goto cleanup;\n    }\n\n    printf(\"Available vulkan layers:\\n\");\n    for (i = 0; i < layer_count; i++) {\n        printf(\"  %s\\n\", available_layers[i].layerName);\n        if (strcmp(validation_layer_name, available_layers[i].layerName) == 0) {\n            ret = true;\n            break;\n        }\n    }\ncleanup:\n    free(available_layers);\n    return ret;\n}\n\nVkResult create_debug_utils_messenger_ext(\n    VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,\n    const VkAllocationCallbacks *pAllocator,\n    VkDebugUtilsMessengerEXT *pDebugMessenger) {\n    PFN_vkCreateDebugUtilsMessengerEXT func =\n        (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(\n            instance, \"vkCreateDebugUtilsMessengerEXT\");\n    if (func != NULL) {\n        return func(instance, pCreateInfo, pAllocator, pDebugMessenger);\n    } else {\n        return VK_ERROR_EXTENSION_NOT_PRESENT;\n    }\n}\n\nbool create_debug_callback(struct vulkan_demo *demo) {\n    VkResult result;\n\n    VkDebugUtilsMessengerCreateInfoEXT create_info;\n    memset(&create_info, 0, sizeof(VkDebugUtilsMessengerCreateInfoEXT));\n    create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;\n    create_info.messageSeverity =\n        VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |\n        VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;\n    create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |\n                              VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |\n                              VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;\n    create_info.pfnUserCallback = vulkan_debug_callback;\n\n    result = create_debug_utils_messenger_ext(demo->instance, &create_info,\n                                              NULL, &demo->debug_messenger);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"create_debug_utils_messenger_ext failed %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nbool create_instance(struct vulkan_demo *demo) {\n    uint32_t i;\n    uint32_t available_instance_extension_count;\n    VkResult result;\n    VkExtensionProperties *available_instance_extensions = NULL;\n    bool ret = false;\n    VkApplicationInfo app_info;\n    VkInstanceCreateInfo create_info;\n    uint32_t glfw_extension_count;\n    const char **glfw_extensions;\n    uint32_t enabled_extension_count;\n    const char **enabled_extensions = NULL;\n    bool validation_layers_installed;\n\n    validation_layers_installed = check_validation_layer_support();\n\n    if (!validation_layers_installed) {\n        fprintf(stdout,\n                \"Couldn't find validation layer %s. Continuing without \"\n                \"validation layers.\\n\",\n                validation_layer_name);\n    }\n    result = vkEnumerateInstanceExtensionProperties(\n        NULL, &available_instance_extension_count, NULL);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumerateInstanceExtensionProperties failed %d\\n\",\n                result);\n        return ret;\n    }\n\n    available_instance_extensions = malloc(available_instance_extension_count *\n                                           sizeof(VkExtensionProperties));\n\n    result = vkEnumerateInstanceExtensionProperties(\n        NULL, &available_instance_extension_count,\n        available_instance_extensions);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumerateInstanceExtensionProperties failed %d\\n\",\n                result);\n        goto cleanup;\n    }\n\n    printf(\"available instance extensions:\\n\");\n    for (i = 0; i < available_instance_extension_count; i++) {\n        printf(\"  %s\\n\", available_instance_extensions[i].extensionName);\n    }\n\n    glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extension_count);\n\n    enabled_extension_count = glfw_extension_count;\n    if (validation_layers_installed) {\n        enabled_extension_count += 1;\n        enabled_extensions = malloc(enabled_extension_count * sizeof(char *));\n        memcpy(enabled_extensions, glfw_extensions,\n               glfw_extension_count * sizeof(char *));\n        enabled_extensions[glfw_extension_count] =\n            VK_EXT_DEBUG_UTILS_EXTENSION_NAME;\n    } else {\n        enabled_extensions = malloc(enabled_extension_count * sizeof(char *));\n        memcpy(enabled_extensions, glfw_extensions,\n               glfw_extension_count * sizeof(char *));\n    }\n\n    printf(\"Trying to enable the following instance extensions: \");\n    for (i = 0; i < enabled_extension_count; i++) {\n        if (i > 0) {\n            printf(\", \");\n        }\n        printf(\"%s\\n\", enabled_extensions[i]);\n    }\n    printf(\"\\n\");\n    for (i = 0; i < enabled_extension_count; i++) {\n        int extension_missing = 1;\n        uint32_t j;\n        for (j = 0; j < available_instance_extension_count; j++) {\n            if (strcmp(enabled_extensions[i],\n                       available_instance_extensions[j].extensionName) == 0) {\n                extension_missing = 0;\n                break;\n            }\n        }\n        if (extension_missing) {\n            fprintf(stderr, \"Extension %s is missing\\n\", enabled_extensions[i]);\n            return ret;\n        }\n    }\n\n    memset(&app_info, 0, sizeof(VkApplicationInfo));\n    app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;\n    app_info.pApplicationName = \"Demo\";\n    app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);\n    app_info.pEngineName = \"No Engine\";\n    app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);\n    app_info.apiVersion = VK_API_VERSION_1_0;\n\n    memset(&create_info, 0, sizeof(VkInstanceCreateInfo));\n    create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;\n    create_info.pApplicationInfo = &app_info;\n    create_info.enabledExtensionCount = enabled_extension_count;\n    create_info.ppEnabledExtensionNames = enabled_extensions;\n    if (validation_layers_installed) {\n        create_info.enabledLayerCount = 1;\n        create_info.ppEnabledLayerNames = &validation_layer_name;\n    }\n    result = vkCreateInstance(&create_info, NULL, &demo->instance);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateInstance result %d\\n\", result);\n        return ret;\n    }\n    if (validation_layers_installed) {\n        ret = create_debug_callback(demo);\n    } else {\n        ret = true;\n    }\ncleanup:\n    if (available_instance_extensions) {\n        free(available_instance_extensions);\n    }\n    if (enabled_extensions) {\n        free(enabled_extensions);\n    }\n\n    return ret;\n}\n\nbool create_surface(struct vulkan_demo *demo) {\n    VkResult result;\n    result = glfwCreateWindowSurface(demo->instance, demo->win, NULL,\n                                     &demo->surface);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"creating vulkan surface failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nbool find_queue_families(VkPhysicalDevice physical_device, VkSurfaceKHR surface,\n                         struct queue_family_indices *indices) {\n    VkResult result;\n    uint32_t queue_family_count = 0;\n    uint32_t i = 0;\n    bool ret = false;\n    VkQueueFamilyProperties *queue_family_properties;\n    VkBool32 present_support;\n\n    vkGetPhysicalDeviceQueueFamilyProperties(physical_device,\n                                             &queue_family_count, NULL);\n\n    queue_family_properties =\n        malloc(queue_family_count * sizeof(VkQueueFamilyProperties));\n    vkGetPhysicalDeviceQueueFamilyProperties(\n        physical_device, &queue_family_count, queue_family_properties);\n\n    for (i = 0; i < queue_family_count; i++) {\n        if (queue_family_properties[i].queueCount == 0) {\n            continue;\n        }\n        if (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {\n            indices->graphics = i;\n        }\n\n        result = vkGetPhysicalDeviceSurfaceSupportKHR(\n            physical_device, i, surface, &present_support);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr,\n                    \"vkGetPhysicalDeviceSurfaceSupportKHR failed with %d\\n\",\n                    result);\n            goto cleanup;\n        }\n        if (present_support == VK_TRUE) {\n            indices->present = i;\n        }\n        if (indices->graphics >= 0 && indices->present >= 0) {\n            break;\n        }\n    }\n    ret = true;\ncleanup:\n    free(queue_family_properties);\n    return ret;\n}\n\nbool query_swap_chain_support(\n    VkPhysicalDevice device, VkSurfaceKHR surface,\n    struct swap_chain_support_details *swap_chain_support) {\n    VkResult result;\n\n    result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(\n        device, surface, &swap_chain_support->capabilities);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr,\n                \"vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed: %d\\n\",\n                result);\n        return false;\n    }\n\n    result = vkGetPhysicalDeviceSurfaceFormatsKHR(\n        device, surface, &swap_chain_support->formats_len, NULL);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkGetPhysicalDeviceSurfaceFormatsKHR failed: %d\\n\",\n                result);\n        return false;\n    }\n\n    if (swap_chain_support->formats_len != 0) {\n        swap_chain_support->formats = malloc(swap_chain_support->formats_len *\n                                             sizeof(VkSurfaceFormatKHR));\n        result = vkGetPhysicalDeviceSurfaceFormatsKHR(\n            device, surface, &swap_chain_support->formats_len,\n            swap_chain_support->formats);\n\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkGetPhysicalDeviceSurfaceFormatsKHR failed: %d\\n\",\n                    result);\n            return false;\n        }\n    }\n\n    result = vkGetPhysicalDeviceSurfacePresentModesKHR(\n        device, surface, &swap_chain_support->present_modes_len, NULL);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr,\n                \"vkGetPhysicalDeviceSurfacePresentModesKHR failed: %d\\n\",\n                result);\n        return false;\n    }\n\n    if (swap_chain_support->present_modes_len != 0) {\n        swap_chain_support->present_modes = malloc(\n            swap_chain_support->present_modes_len * sizeof(VkPresentModeKHR));\n        result = vkGetPhysicalDeviceSurfacePresentModesKHR(\n            device, surface, &swap_chain_support->present_modes_len,\n            swap_chain_support->present_modes);\n\n        if (result != VK_SUCCESS) {\n            fprintf(stderr,\n                    \"vkGetPhysicalDeviceSurfacePresentModesKHR failed: %d\\n\",\n                    result);\n            return false;\n        }\n    }\n\n    return true;\n}\n\nbool is_suitable_physical_device(VkPhysicalDevice physical_device,\n                                 VkSurfaceKHR surface,\n                                 struct queue_family_indices *indices) {\n    VkResult result;\n    uint32_t device_extension_count;\n    uint32_t i;\n    VkExtensionProperties *device_extensions;\n    bool ret = false;\n    struct swap_chain_support_details swap_chain_support;\n    int found_khr_surface = 0;\n\n    VkPhysicalDeviceProperties device_properties;\n    vkGetPhysicalDeviceProperties(physical_device, &device_properties);\n\n    printf(\"Probing physical device %s\\n\", device_properties.deviceName);\n\n    result = vkEnumerateDeviceExtensionProperties(\n        physical_device, NULL, &device_extension_count, NULL);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumerateDeviceExtensionProperties failed: %d\\n\",\n                result);\n        return false;\n    }\n\n    device_extensions =\n        malloc(device_extension_count * sizeof(VkExtensionProperties));\n\n    result = vkEnumerateDeviceExtensionProperties(\n        physical_device, NULL, &device_extension_count, device_extensions);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumerateDeviceExtensionProperties failed: %d\\n\",\n                result);\n        goto cleanup;\n    }\n\n    printf(\"  Supported device extensions:\\n\");\n\n    for (i = 0; i < device_extension_count; i++) {\n        printf(\"    %s\\n\", device_extensions[i].extensionName);\n        if (strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,\n                   device_extensions[i].extensionName) == 0) {\n            found_khr_surface = 1;\n            break;\n        }\n    }\n    if (!found_khr_surface) {\n        printf(\"  Device doesnt support %s\\n\", VK_KHR_SWAPCHAIN_EXTENSION_NAME);\n        goto cleanup;\n    }\n    if (!find_queue_families(physical_device, surface, indices)) {\n        goto cleanup;\n    }\n    if (indices->graphics < 0 || indices->present < 0) {\n        printf(\"  Device is missing graphics and/or present support. graphics: \"\n               \"%d, present: %d\\n\",\n               indices->graphics, indices->present);\n        goto cleanup;\n    }\n\n    if (!query_swap_chain_support(physical_device, surface,\n                                  &swap_chain_support)) {\n        goto cleanup;\n    }\n\n    if (swap_chain_support.formats_len == 0) {\n        printf(\" Device doesn't support any swap chain formats\\n\");\n        goto cleanup;\n    }\n\n    if (swap_chain_support.present_modes_len == 0) {\n        printf(\" Device doesn't support any swap chain present modes\\n\");\n        goto cleanup;\n    }\n    ret = true;\n\ncleanup:\n    free(device_extensions);\n    swap_chain_support_details_free(&swap_chain_support);\n\n    return ret;\n}\n\nbool create_physical_device(struct vulkan_demo *demo) {\n    uint32_t device_count = 0;\n    VkPhysicalDevice *physical_devices;\n    VkResult result;\n    uint32_t i;\n    bool ret = false;\n\n    result = vkEnumeratePhysicalDevices(demo->instance, &device_count, NULL);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumeratePhysicalDevices failed: %d\\n\", result);\n        return ret;\n    }\n    if (device_count == 0) {\n        fprintf(stderr, \"no vulkan capable GPU found!\");\n        return ret;\n    }\n\n    physical_devices = malloc(device_count * sizeof(VkPhysicalDevice));\n    result = vkEnumeratePhysicalDevices(demo->instance, &device_count,\n                                        physical_devices);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumeratePhysicalDevices failed: %d\\n\", result);\n        goto cleanup;\n    }\n\n    for (i = 0; i < device_count; i++) {\n        struct queue_family_indices indices = {-1, -1};\n        if (is_suitable_physical_device(physical_devices[i], demo->surface,\n                                        &indices)) {\n            printf(\"  Selecting this device for rendering. Queue families: \"\n                   \"graphics: %d, present: %d!\\n\",\n                   indices.graphics, indices.present);\n            demo->physical_device = physical_devices[i];\n            demo->indices = indices;\n            break;\n        }\n    }\n    if (demo->physical_device == NULL) {\n        fprintf(stderr, \"failed to find a suitable GPU!\\n\");\n    } else {\n        ret = true;\n    }\ncleanup:\n    free(physical_devices);\n    return ret;\n}\n\nbool create_logical_device(struct vulkan_demo *demo) {\n    VkResult result;\n    bool ret = false;\n    float queuePriority = 1.0f;\n    uint32_t num_queues = 1;\n    VkDeviceQueueCreateInfo *queue_create_infos;\n    VkDeviceCreateInfo create_info;\n    const char *swap_chain_extension_name = VK_KHR_SWAPCHAIN_EXTENSION_NAME;\n\n    queue_create_infos = calloc(2, sizeof(VkDeviceQueueCreateInfo));\n    queue_create_infos[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;\n    queue_create_infos[0].queueFamilyIndex = demo->indices.graphics;\n    queue_create_infos[0].queueCount = 1;\n    queue_create_infos[0].pQueuePriorities = &queuePriority;\n\n    if (demo->indices.present != demo->indices.graphics) {\n        queue_create_infos[1].sType =\n            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;\n        queue_create_infos[1].queueFamilyIndex = demo->indices.present;\n        queue_create_infos[1].queueCount = 1;\n        queue_create_infos[1].pQueuePriorities = &queuePriority;\n        num_queues = 2;\n    }\n\n    memset(&create_info, 0, sizeof(VkDeviceCreateInfo));\n    create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;\n    create_info.queueCreateInfoCount = num_queues;\n    create_info.pQueueCreateInfos = queue_create_infos;\n    create_info.enabledExtensionCount = 1;\n    create_info.ppEnabledExtensionNames = &swap_chain_extension_name;\n\n    result = vkCreateDevice(demo->physical_device, &create_info, NULL,\n                            &demo->device);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateDevice failed: %d\\n\", result);\n        goto cleanup;\n    }\n\n    vkGetDeviceQueue(demo->device, demo->indices.graphics, 0,\n                     &demo->graphics_queue);\n    vkGetDeviceQueue(demo->device, demo->indices.present, 0,\n                     &demo->present_queue);\n    ret = true;\ncleanup:\n    free(queue_create_infos);\n    return ret;\n}\n\nbool create_sampler(struct vulkan_demo *demo) {\n    VkResult result;\n    VkSamplerCreateInfo sampler_info;\n\n    memset(&sampler_info, 0, sizeof(VkSamplerCreateInfo));\n    sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n    sampler_info.pNext = NULL;\n    sampler_info.maxAnisotropy = 1.0;\n    sampler_info.magFilter = VK_FILTER_LINEAR;\n    sampler_info.minFilter = VK_FILTER_LINEAR;\n    sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n    sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.mipLodBias = 0.0f;\n    sampler_info.compareEnable = VK_FALSE;\n    sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;\n    sampler_info.minLod = 0.0f;\n    sampler_info.maxLod = 0.0f;\n    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;\n\n    result = vkCreateSampler(demo->device, &sampler_info, NULL, &demo->sampler);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateSampler failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nVkSurfaceFormatKHR\nchoose_swap_surface_format(VkSurfaceFormatKHR *available_formats,\n                           uint32_t available_formats_len) {\n    VkSurfaceFormatKHR undefined_format = {VK_FORMAT_B8G8R8A8_UNORM,\n                                           VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};\n    uint32_t i;\n    if (available_formats_len == 1 &&\n        available_formats[0].format == VK_FORMAT_UNDEFINED) {\n        return undefined_format;\n    }\n\n    for (i = 0; i < available_formats_len; i++) {\n        if (available_formats[i].format == VK_FORMAT_B8G8R8A8_UNORM &&\n            available_formats[i].colorSpace ==\n                VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {\n            return available_formats[i];\n        }\n    }\n\n    return available_formats[0];\n}\n\nVkPresentModeKHR\nchoose_swap_present_mode(VkPresentModeKHR *available_present_modes,\n                         uint32_t available_present_modes_len) {\n    uint32_t i;\n    for (i = 0; i < available_present_modes_len; i++) {\n        /*\n        best mode to ensure good input latency while ensuring we are not\n        producing tearing\n        */\n        if (available_present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {\n            return available_present_modes[i];\n        }\n    }\n\n    /* must be supported */\n    return VK_PRESENT_MODE_FIFO_KHR;\n}\n\nVkExtent2D choose_swap_extent(struct vulkan_demo *demo,\n                              VkSurfaceCapabilitiesKHR *capabilities) {\n    int width, height;\n    VkExtent2D actual_extent;\n    if (capabilities->currentExtent.width != 0xFFFFFFFF) {\n        return capabilities->currentExtent;\n    } else {\n        /* not window size! */\n        glfwGetFramebufferSize(demo->win, &width, &height);\n\n        actual_extent.width = (uint32_t)width;\n        actual_extent.height = (uint32_t)height;\n\n        actual_extent.width = NK_MAX(\n            capabilities->minImageExtent.width,\n            NK_MIN(capabilities->maxImageExtent.width, actual_extent.width));\n        actual_extent.height = NK_MAX(\n            capabilities->minImageExtent.height,\n            NK_MIN(capabilities->maxImageExtent.height, actual_extent.height));\n\n        return actual_extent;\n    }\n}\n\nbool create_swap_chain(struct vulkan_demo *demo) {\n    struct swap_chain_support_details swap_chain_support;\n    VkSurfaceFormatKHR surface_format;\n    VkPresentModeKHR present_mode;\n    VkExtent2D extent;\n    VkResult result;\n    VkSwapchainCreateInfoKHR create_info;\n    uint32_t queue_family_indices[2];\n    bool ret = false;\n\n    queue_family_indices[0] = (uint32_t)demo->indices.graphics;\n    queue_family_indices[1] = (uint32_t)demo->indices.present;\n\n    if (!query_swap_chain_support(demo->physical_device, demo->surface,\n                                  &swap_chain_support)) {\n        goto cleanup;\n    }\n    surface_format = choose_swap_surface_format(swap_chain_support.formats,\n                                                swap_chain_support.formats_len);\n    present_mode = choose_swap_present_mode(\n        swap_chain_support.present_modes, swap_chain_support.present_modes_len);\n    extent = choose_swap_extent(demo, &swap_chain_support.capabilities);\n\n    demo->swap_chain_images_len =\n        swap_chain_support.capabilities.minImageCount + 1;\n    if (swap_chain_support.capabilities.maxImageCount > 0 &&\n        demo->swap_chain_images_len >\n            swap_chain_support.capabilities.maxImageCount) {\n        demo->swap_chain_images_len =\n            swap_chain_support.capabilities.maxImageCount;\n    }\n\n    memset(&create_info, 0, sizeof(VkSwapchainCreateInfoKHR));\n    create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;\n    create_info.surface = demo->surface;\n\n    create_info.minImageCount = demo->swap_chain_images_len;\n    create_info.imageFormat = surface_format.format;\n    create_info.imageColorSpace = surface_format.colorSpace;\n    create_info.imageExtent = extent;\n    create_info.imageArrayLayers = 1;\n    create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;\n\n    if (demo->indices.graphics != demo->indices.present) {\n        create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;\n        create_info.queueFamilyIndexCount = 2;\n        create_info.pQueueFamilyIndices = queue_family_indices;\n    } else {\n        create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;\n    }\n\n    create_info.preTransform = swap_chain_support.capabilities.currentTransform;\n        \n    if(swap_chain_support.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {\n    \tcreate_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;\n    } else if(swap_chain_support.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) {\n    \tcreate_info.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;\n    } else if(swap_chain_support.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) {\n    \tcreate_info.compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;\n    } else if(swap_chain_support.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {\n    \tcreate_info.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;\n    }\n    \n    create_info.presentMode = present_mode;\n    create_info.clipped = VK_TRUE;\n\n    result = vkCreateSwapchainKHR(demo->device, &create_info, NULL,\n                                  &demo->swap_chain);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateSwapchainKHR failed: %d\\n\", result);\n        goto cleanup;\n    }\n\n    result = vkGetSwapchainImagesKHR(demo->device, demo->swap_chain,\n                                     &demo->swap_chain_images_len, NULL);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkGetSwapchainImagesKHR failed: %d\\n\", result);\n        goto cleanup;\n    }\n    if (demo->swap_chain_images == NULL) {\n        demo->swap_chain_images =\n            malloc(demo->swap_chain_images_len * sizeof(VkImage));\n    }\n    result = vkGetSwapchainImagesKHR(demo->device, demo->swap_chain,\n                                     &demo->swap_chain_images_len,\n                                     demo->swap_chain_images);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkGetSwapchainImagesKHR failed: %d\\n\", result);\n        return false;\n    }\n\n    demo->swap_chain_image_format = surface_format.format;\n    demo->swap_chain_image_extent = extent;\n\n    ret = true;\ncleanup:\n    swap_chain_support_details_free(&swap_chain_support);\n\n    return ret;\n}\n\nbool create_swap_chain_image_views(struct vulkan_demo *demo) {\n    uint32_t i;\n    VkResult result;\n    VkImageViewCreateInfo create_info;\n\n    memset(&create_info, 0, sizeof(VkImageViewCreateInfo));\n    create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n    create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n    create_info.format = demo->swap_chain_image_format;\n    create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;\n    create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;\n    create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;\n    create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;\n    create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    create_info.subresourceRange.baseMipLevel = 0;\n    create_info.subresourceRange.levelCount = 1;\n    create_info.subresourceRange.baseArrayLayer = 0;\n    create_info.subresourceRange.layerCount = 1;\n\n    if (!demo->swap_chain_image_views) {\n        demo->swap_chain_image_views =\n            malloc(demo->swap_chain_images_len * sizeof(VkImageView));\n    }\n\n    for (i = 0; i < demo->swap_chain_images_len; i++) {\n        create_info.image = demo->swap_chain_images[i];\n        result = vkCreateImageView(demo->device, &create_info, NULL,\n                                   &demo->swap_chain_image_views[i]);\n\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateImageView failed: %d\\n\", result);\n            return false;\n        }\n    }\n    return true;\n}\n\nbool create_overlay_images(struct vulkan_demo *demo) {\n    uint32_t i, j;\n    VkResult result;\n    VkMemoryRequirements mem_requirements;\n    VkPhysicalDeviceMemoryProperties mem_properties;\n    int found;\n    VkImageCreateInfo image_info;\n    VkMemoryAllocateInfo alloc_info;\n    VkImageViewCreateInfo image_view_info;\n\n    memset(&image_info, 0, sizeof(VkImageCreateInfo));\n    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n    image_info.imageType = VK_IMAGE_TYPE_2D;\n    image_info.extent.width = demo->swap_chain_image_extent.width;\n    image_info.extent.height = demo->swap_chain_image_extent.height;\n    image_info.extent.depth = 1;\n    image_info.mipLevels = 1;\n    image_info.arrayLayers = 1;\n    image_info.format = demo->swap_chain_image_format;\n    image_info.tiling = VK_IMAGE_TILING_OPTIMAL;\n    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    image_info.usage =\n        VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;\n    image_info.samples = VK_SAMPLE_COUNT_1_BIT;\n    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n\n    memset(&image_view_info, 0, sizeof(VkImageViewCreateInfo));\n    image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n    image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n    image_view_info.format = demo->swap_chain_image_format;\n    image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    image_view_info.subresourceRange.baseMipLevel = 0;\n    image_view_info.subresourceRange.levelCount = 1;\n    image_view_info.subresourceRange.baseArrayLayer = 0;\n    image_view_info.subresourceRange.layerCount = 1;\n\n    if (!demo->overlay_images) {\n        demo->overlay_images =\n            malloc(demo->swap_chain_images_len * sizeof(VkImage));\n    }\n\n    if (!demo->overlay_image_memories) {\n        demo->overlay_image_memories =\n            malloc(demo->swap_chain_images_len * sizeof(VkDeviceMemory));\n    }\n    if (!demo->overlay_image_views) {\n        demo->overlay_image_views =\n            malloc(demo->swap_chain_images_len * sizeof(VkImageView));\n    }\n\n    for (i = 0; i < demo->swap_chain_images_len; i++) {\n        result = vkCreateImage(demo->device, &image_info, NULL,\n                               &demo->overlay_images[i]);\n\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateImage failed for index %lu: %d\\n\",\n                    (unsigned long)i, result);\n            return false;\n        }\n\n        vkGetImageMemoryRequirements(demo->device, demo->overlay_images[i],\n                                     &mem_requirements);\n\n        alloc_info.allocationSize = mem_requirements.size;\n\n        vkGetPhysicalDeviceMemoryProperties(demo->physical_device,\n                                            &mem_properties);\n        found = 0;\n        for (j = 0; j < mem_properties.memoryTypeCount; j++) {\n            if ((mem_requirements.memoryTypeBits & (1 << j)) &&\n                (mem_properties.memoryTypes[j].propertyFlags &\n                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ==\n                    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {\n                found = 1;\n                break;\n            }\n        }\n        if (!found) {\n            fprintf(stderr,\n                    \"failed to find suitable memory type for index %lu!\\n\",\n                    (unsigned long)i);\n            return false;\n        }\n        alloc_info.memoryTypeIndex = j;\n        result = vkAllocateMemory(demo->device, &alloc_info, NULL,\n                                  &demo->overlay_image_memories[i]);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr,\n                    \"failed to allocate vulkan memory for index %lu: %d!\\n\",\n                    (unsigned long)i, result);\n            return false;\n        }\n        result = vkBindImageMemory(demo->device, demo->overlay_images[i],\n                                   demo->overlay_image_memories[i], 0);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"Couldn't bind image memory for index %lu: %d\\n\",\n                    (unsigned long)i, result);\n            return false;\n        }\n\n        image_view_info.image = demo->overlay_images[i];\n        result = vkCreateImageView(demo->device, &image_view_info, NULL,\n                                   &demo->overlay_image_views[i]);\n\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateImageView failed for index %lu: %d\\n\",\n                    (unsigned long)i, result);\n            return false;\n        }\n    }\n    return true;\n}\n\nbool create_render_pass(struct vulkan_demo *demo) {\n    VkAttachmentDescription attachment;\n    VkAttachmentReference color_attachment_ref;\n    VkSubpassDescription subpass;\n    VkSubpassDependency dependency;\n    VkRenderPassCreateInfo render_pass_info;\n    VkResult result;\n\n    memset(&attachment, 0, sizeof(VkAttachmentDescription));\n    attachment.format = demo->swap_chain_image_format;\n    attachment.samples = VK_SAMPLE_COUNT_1_BIT;\n    attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;\n    attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n    attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n    attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n    attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;\n\n    memset(&color_attachment_ref, 0, sizeof(VkAttachmentReference));\n    color_attachment_ref.attachment = 0;\n    color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;\n\n    memset(&subpass, 0, sizeof(VkSubpassDescription));\n    subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;\n    subpass.colorAttachmentCount = 1;\n    subpass.pColorAttachments = &color_attachment_ref;\n\n    memset(&dependency, 0, sizeof(VkSubpassDependency));\n    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;\n    dependency.dstSubpass = 0;\n    dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    dependency.srcAccessMask = 0;\n    dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |\n                               VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n\n    memset(&render_pass_info, 0, sizeof(VkRenderPassCreateInfo));\n    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;\n    render_pass_info.attachmentCount = 1;\n    render_pass_info.pAttachments = &attachment;\n    render_pass_info.subpassCount = 1;\n    render_pass_info.pSubpasses = &subpass;\n    render_pass_info.dependencyCount = 1;\n    render_pass_info.pDependencies = &dependency;\n\n    result = vkCreateRenderPass(demo->device, &render_pass_info, NULL,\n                                &demo->render_pass);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateRenderPass failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nbool create_framebuffers(struct vulkan_demo *demo) {\n    uint32_t i;\n    VkResult result;\n    VkFramebufferCreateInfo framebuffer_info;\n\n    if (!demo->framebuffers) {\n        demo->framebuffers =\n            malloc(demo->swap_chain_images_len * sizeof(VkFramebuffer));\n    }\n\n    memset(&framebuffer_info, 0, sizeof(VkFramebufferCreateInfo));\n    framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;\n    framebuffer_info.renderPass = demo->render_pass;\n    framebuffer_info.attachmentCount = 1;\n    framebuffer_info.width = demo->swap_chain_image_extent.width;\n    framebuffer_info.height = demo->swap_chain_image_extent.height;\n    framebuffer_info.layers = 1;\n\n    for (i = 0; i < demo->swap_chain_images_len; i++) {\n        framebuffer_info.pAttachments = &demo->swap_chain_image_views[i];\n\n        result = vkCreateFramebuffer(demo->device, &framebuffer_info, NULL,\n                                     &demo->framebuffers[i]);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateFramebuffer failed from index %lu: %d\\n\",\n                    (unsigned long)i, result);\n            return false;\n        }\n    }\n    return true;\n}\n\nbool create_descriptor_set_layout(struct vulkan_demo *demo) {\n    VkDescriptorSetLayoutBinding overlay_layout_binding;\n    VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_nfo;\n    VkResult result;\n\n    memset(&overlay_layout_binding, 0, sizeof(VkDescriptorSetLayoutBinding));\n    overlay_layout_binding.binding = 0;\n    overlay_layout_binding.descriptorCount = 1;\n    overlay_layout_binding.descriptorType =\n        VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    overlay_layout_binding.pImmutableSamplers = NULL;\n    overlay_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;\n\n    memset(&descriptor_set_layout_create_nfo, 0,\n           sizeof(VkDescriptorSetLayoutCreateInfo));\n    descriptor_set_layout_create_nfo.sType =\n        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n    descriptor_set_layout_create_nfo.bindingCount = 1;\n    descriptor_set_layout_create_nfo.pBindings = &overlay_layout_binding;\n\n    result = vkCreateDescriptorSetLayout(demo->device,\n                                         &descriptor_set_layout_create_nfo,\n                                         NULL, &demo->descriptor_set_layout);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateDescriptorSetLayout failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nbool create_descriptor_pool(struct vulkan_demo *demo) {\n    VkDescriptorPoolSize pool_size;\n    VkDescriptorPoolCreateInfo pool_info;\n    VkResult result;\n\n    memset(&pool_size, 0, sizeof(VkDescriptorPoolSize));\n    pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    pool_size.descriptorCount = demo->swap_chain_images_len;\n\n    memset(&pool_info, 0, sizeof(VkDescriptorPoolCreateInfo));\n    pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;\n    pool_info.poolSizeCount = 1;\n    pool_info.pPoolSizes = &pool_size;\n    pool_info.maxSets = demo->swap_chain_images_len;\n    result = vkCreateDescriptorPool(demo->device, &pool_info, NULL,\n                                    &demo->descriptor_pool);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateDescriptorPool failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nvoid update_descriptor_sets(struct vulkan_demo *demo) {\n    uint32_t i;\n    VkDescriptorImageInfo descriptor_image_info;\n    VkWriteDescriptorSet descriptor_write;\n\n    memset(&descriptor_image_info, 0, sizeof(VkDescriptorImageInfo));\n    descriptor_image_info.imageLayout =\n        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n    descriptor_image_info.sampler = demo->sampler;\n\n    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));\n    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n    descriptor_write.dstBinding = 0;\n    descriptor_write.dstArrayElement = 0;\n    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    descriptor_write.descriptorCount = 1;\n    descriptor_write.pImageInfo = &descriptor_image_info;\n\n    for (i = 0; i < demo->swap_chain_images_len; i++) {\n        descriptor_write.dstSet = demo->descriptor_sets[i];\n        descriptor_image_info.imageView = demo->overlay_image_views[i];\n\n        vkUpdateDescriptorSets(demo->device, 1, &descriptor_write, 0, NULL);\n    }\n}\n\nbool create_descriptor_sets(struct vulkan_demo *demo) {\n    bool ret = false;\n    VkDescriptorSetLayout *descriptor_set_layouts;\n    VkDescriptorSetAllocateInfo alloc_info;\n    uint32_t i;\n    VkResult result;\n\n    demo->descriptor_sets =\n        malloc(demo->swap_chain_images_len * sizeof(VkDescriptorSet));\n    descriptor_set_layouts =\n        malloc(demo->swap_chain_images_len * sizeof(VkDescriptorSetLayout));\n\n    for (i = 0; i < demo->swap_chain_images_len; i++) {\n        descriptor_set_layouts[i] = demo->descriptor_set_layout;\n    }\n\n    memset(&alloc_info, 0, sizeof(VkDescriptorSetAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n    alloc_info.descriptorPool = demo->descriptor_pool;\n    alloc_info.descriptorSetCount = demo->swap_chain_images_len;\n    alloc_info.pSetLayouts = descriptor_set_layouts;\n    result = vkAllocateDescriptorSets(demo->device, &alloc_info,\n                                      demo->descriptor_sets);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkAllocateDescriptorSets failed: %d\\n\", result);\n        goto cleanup;\n    }\n\n    update_descriptor_sets(demo);\n\n    ret = true;\ncleanup:\n    free(descriptor_set_layouts);\n\n    return ret;\n}\n\nbool create_shader_module(VkDevice device, char *shader_buffer,\n                          size_t shader_buffer_len,\n                          VkShaderModule *shader_module) {\n    VkShaderModuleCreateInfo create_info;\n    VkResult result;\n\n    memset(&create_info, 0, sizeof(VkShaderModuleCreateInfo));\n    create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;\n    create_info.codeSize = shader_buffer_len;\n    create_info.pCode = (const uint32_t *)shader_buffer;\n\n    result = vkCreateShaderModule(device, &create_info, NULL, shader_module);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateShaderModule failed: %d\\n\", result);\n        return false;\n    }\n\n    return true;\n}\n\nbool create_graphics_pipeline(struct vulkan_demo *demo) {\n    bool ret = false;\n    char *vert_shader_code = NULL;\n    char *frag_shader_code = NULL;\n    VkShaderModule vert_shader_module = VK_NULL_HANDLE;\n    VkShaderModule frag_shader_module = VK_NULL_HANDLE;\n    FILE *fp;\n    size_t file_len;\n    VkPipelineShaderStageCreateInfo vert_shader_stage_info;\n    VkPipelineShaderStageCreateInfo frag_shader_stage_info;\n    VkPipelineShaderStageCreateInfo shader_stages[2];\n    VkPipelineVertexInputStateCreateInfo vertex_input_info;\n    VkPipelineInputAssemblyStateCreateInfo input_assembly;\n    VkViewport viewport;\n    VkRect2D scissor;\n    VkPipelineViewportStateCreateInfo viewport_state;\n    VkPipelineRasterizationStateCreateInfo rasterizer;\n    VkPipelineMultisampleStateCreateInfo multisampling;\n    VkPipelineColorBlendAttachmentState color_blend_attachment;\n    VkPipelineColorBlendStateCreateInfo color_blending;\n    VkPipelineLayoutCreateInfo pipeline_layout_info;\n    VkResult result;\n    VkGraphicsPipelineCreateInfo pipeline_info;\n    size_t read_result;\n\n    fp = fopen(\"shaders/demo.vert.spv\", \"rb\");\n    if (!fp) {\n        fprintf(stderr, \"Couldn't open shaders/demo.vert.spv\\n\");\n        return false;\n    }\n    fseek(fp, 0, SEEK_END);\n    file_len = ftell(fp);\n    vert_shader_code = malloc(file_len);\n    fseek(fp, 0, 0);\n    read_result = fread(vert_shader_code, file_len, 1, fp);\n    fclose(fp);\n    if (read_result != 1) {\n        fprintf(stderr, \"Could not read fragment shader\\n\");\n        goto cleanup;\n    }\n\n    if (!create_shader_module(demo->device, vert_shader_code, file_len,\n                              &vert_shader_module)) {\n        goto cleanup;\n    }\n\n    fp = fopen(\"shaders/demo.frag.spv\", \"rb\");\n    if (!fp) {\n        fprintf(stderr, \"Couldn't open shaders/demo.frag.spv\\n\");\n        return false;\n    }\n    fseek(fp, 0, SEEK_END);\n    file_len = ftell(fp);\n    frag_shader_code = malloc(file_len);\n    fseek(fp, 0, 0);\n    read_result = fread(frag_shader_code, file_len, 1, fp);\n    fclose(fp);\n    if (read_result != 1) {\n        fprintf(stderr, \"Could not read fragment shader\\n\");\n        goto cleanup;\n    }\n\n    if (!create_shader_module(demo->device, frag_shader_code, file_len,\n                              &frag_shader_module)) {\n        goto cleanup;\n    }\n\n    memset(&vert_shader_stage_info, 0, sizeof(VkPipelineShaderStageCreateInfo));\n    vert_shader_stage_info.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;\n    vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;\n    vert_shader_stage_info.module = vert_shader_module;\n    vert_shader_stage_info.pName = \"main\";\n\n    memset(&frag_shader_stage_info, 0, sizeof(VkPipelineShaderStageCreateInfo));\n    frag_shader_stage_info.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;\n    frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;\n    frag_shader_stage_info.module = frag_shader_module;\n    frag_shader_stage_info.pName = \"main\";\n\n    shader_stages[0] = vert_shader_stage_info;\n    shader_stages[1] = frag_shader_stage_info;\n\n    memset(&vertex_input_info, 0, sizeof(VkPipelineVertexInputStateCreateInfo));\n    vertex_input_info.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;\n\n    memset(&input_assembly, 0, sizeof(VkPipelineInputAssemblyStateCreateInfo));\n    input_assembly.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;\n    input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;\n    input_assembly.primitiveRestartEnable = VK_FALSE;\n\n    memset(&viewport, 0, sizeof(VkViewport));\n    viewport.x = 0.0f;\n    viewport.y = 0.0f;\n    viewport.width = (float)demo->swap_chain_image_extent.width;\n    viewport.height = (float)demo->swap_chain_image_extent.height;\n    viewport.minDepth = 0.0f;\n    viewport.maxDepth = 1.0f;\n\n    memset(&scissor, 0, sizeof(VkRect2D));\n    scissor.extent.width = demo->swap_chain_image_extent.width;\n    scissor.extent.height = demo->swap_chain_image_extent.height;\n\n    memset(&viewport_state, 0, sizeof(VkPipelineViewportStateCreateInfo));\n    viewport_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;\n    viewport_state.viewportCount = 1;\n    viewport_state.pViewports = &viewport;\n    viewport_state.scissorCount = 1;\n    viewport_state.pScissors = &scissor;\n\n    memset(&rasterizer, 0, sizeof(VkPipelineRasterizationStateCreateInfo));\n    rasterizer.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;\n    rasterizer.depthClampEnable = VK_FALSE;\n    rasterizer.rasterizerDiscardEnable = VK_FALSE;\n    rasterizer.polygonMode = VK_POLYGON_MODE_FILL;\n    rasterizer.lineWidth = 1.0f;\n    rasterizer.cullMode = VK_CULL_MODE_FRONT_BIT;\n    rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;\n    rasterizer.depthBiasEnable = VK_FALSE;\n\n    memset(&multisampling, 0, sizeof(VkPipelineMultisampleStateCreateInfo));\n    multisampling.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;\n    multisampling.sampleShadingEnable = VK_FALSE;\n    multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;\n\n    memset(&color_blend_attachment, 0,\n           sizeof(VkPipelineColorBlendAttachmentState));\n    color_blend_attachment.colorWriteMask =\n        VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |\n        VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;\n    color_blend_attachment.blendEnable = VK_TRUE;\n    color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;\n    color_blend_attachment.dstColorBlendFactor =\n        VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;\n    color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;\n    color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;\n    color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;\n    color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;\n\n    memset(&color_blending, 0, sizeof(VkPipelineColorBlendStateCreateInfo));\n    color_blending.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;\n    color_blending.logicOpEnable = VK_FALSE;\n    color_blending.logicOp = VK_LOGIC_OP_COPY;\n    color_blending.attachmentCount = 1;\n    color_blending.pAttachments = &color_blend_attachment;\n    color_blending.blendConstants[0] = 1.0f;\n    color_blending.blendConstants[1] = 1.0f;\n    color_blending.blendConstants[2] = 1.0f;\n    color_blending.blendConstants[3] = 1.0f;\n\n    memset(&pipeline_layout_info, 0, sizeof(VkPipelineLayoutCreateInfo));\n    pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;\n    pipeline_layout_info.setLayoutCount = 0;\n    pipeline_layout_info.pushConstantRangeCount = 0;\n    pipeline_layout_info.setLayoutCount = 1;\n    pipeline_layout_info.pSetLayouts = &demo->descriptor_set_layout;\n\n    result = vkCreatePipelineLayout(demo->device, &pipeline_layout_info, NULL,\n                                    &demo->pipeline_layout);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreatePipelineLayout failed: %d\\n\", result);\n        goto cleanup;\n    }\n\n    memset(&pipeline_info, 0, sizeof(VkGraphicsPipelineCreateInfo));\n    pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;\n    pipeline_info.stageCount = 2;\n    pipeline_info.pStages = shader_stages;\n    pipeline_info.pVertexInputState = &vertex_input_info;\n    pipeline_info.pInputAssemblyState = &input_assembly;\n    pipeline_info.pViewportState = &viewport_state;\n    pipeline_info.pRasterizationState = &rasterizer;\n    pipeline_info.pMultisampleState = &multisampling;\n    pipeline_info.pColorBlendState = &color_blending;\n    pipeline_info.layout = demo->pipeline_layout;\n    pipeline_info.renderPass = demo->render_pass;\n    pipeline_info.basePipelineHandle = NULL;\n\n    result = vkCreateGraphicsPipelines(demo->device, NULL, 1, &pipeline_info,\n                                       NULL, &demo->pipeline);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateGraphicsPipelines failed: %d\\n\", result);\n        goto cleanup;\n    }\n    ret = true;\ncleanup:\n    if (frag_shader_module) {\n        vkDestroyShaderModule(demo->device, frag_shader_module, NULL);\n    }\n    if (frag_shader_code) {\n        free(frag_shader_code);\n    }\n    if (vert_shader_module) {\n        vkDestroyShaderModule(demo->device, vert_shader_module, NULL);\n    }\n    if (vert_shader_code) {\n        free(vert_shader_code);\n    }\n\n    return ret;\n}\n\nbool create_command_pool(struct vulkan_demo *demo) {\n    VkCommandPoolCreateInfo pool_info;\n    VkResult result;\n\n    memset(&pool_info, 0, sizeof(VkCommandPoolCreateInfo));\n    pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;\n    pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;\n    pool_info.queueFamilyIndex = demo->indices.graphics;\n\n    result = vkCreateCommandPool(demo->device, &pool_info, NULL,\n                                 &demo->command_pool);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateCommandPool failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nbool create_command_buffers(struct vulkan_demo *demo) {\n    VkCommandBufferAllocateInfo alloc_info;\n    VkResult result;\n\n    demo->command_buffers =\n        malloc(MAX_IN_FLIGHT_FRAMES * sizeof(VkCommandBuffer));\n\n    memset(&alloc_info, 0, sizeof(VkCommandBufferAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;\n    alloc_info.commandPool = demo->command_pool;\n    alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;\n    alloc_info.commandBufferCount = MAX_IN_FLIGHT_FRAMES;\n\n    result = vkAllocateCommandBuffers(demo->device, &alloc_info,\n                                      demo->command_buffers);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkAllocateCommandBuffers failed: %d\\n\", result);\n        return false;\n    }\n\n    return true;\n}\n\nbool create_semaphores(struct vulkan_demo *demo) {\n    VkSemaphoreCreateInfo semaphore_info;\n    VkResult result;\n    uint32_t i;\n    \n    demo->image_available = (VkSemaphore*)malloc(MAX_IN_FLIGHT_FRAMES * sizeof(VkSemaphore));\n    demo->render_finished = (VkSemaphore*)malloc(demo->swap_chain_images_len * sizeof(VkSemaphore));\n    memset(&semaphore_info, 0, sizeof(VkSemaphoreCreateInfo));\n    semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;\n    \n    for(i = 0; i < MAX_IN_FLIGHT_FRAMES; i++) {\n        result = vkCreateSemaphore(demo->device, &semaphore_info, NULL,\n                               &demo->image_available[i]);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateSemaphore failed: %d\\n\", result);\n            return false;\n        }\n    }\n    for(i = 0; i < demo->swap_chain_images_len; i++) {\n        result = vkCreateSemaphore(demo->device, &semaphore_info, NULL,\n                               &demo->render_finished[i]);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateSemaphore failed: %d\\n\", result);\n            return false;\n        }\n    }\n    return true;\n}\n\nbool create_fence(struct vulkan_demo *demo) {\n    VkResult result;\n    VkFenceCreateInfo fence_create_info;\n    uint32_t i;\n    \n    demo->render_fence = (VkFence*)malloc(MAX_IN_FLIGHT_FRAMES * sizeof(VkFence));\n\n    memset(&fence_create_info, 0, sizeof(VkFenceCreateInfo));\n    fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;\n    fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;\n    \n    for(i = 0; i < MAX_IN_FLIGHT_FRAMES; i++) {\n        result = vkCreateFence(demo->device, &fence_create_info, NULL,\n                           &demo->render_fence[i]);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateFence failed: %d\\n\", result);\n            return false;\n        }\n    }\n    return true;\n}\n\nbool create_swap_chain_related_resources(struct vulkan_demo *demo) {\n    if (!create_swap_chain(demo)) {\n        return false;\n    }\n    if (!create_swap_chain_image_views(demo)) {\n        return false;\n    }\n    if (!create_overlay_images(demo)) {\n        return false;\n    }\n    if (!create_render_pass(demo)) {\n        return false;\n    }\n    if (!create_framebuffers(demo)) {\n        return false;\n    }\n    if (!create_graphics_pipeline(demo)) {\n        return false;\n    }\n    return true;\n}\n\nbool destroy_swap_chain_related_resources(struct vulkan_demo *demo) {\n    uint32_t i;\n    VkResult result;\n\n    result = vkQueueWaitIdle(demo->graphics_queue);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkQueueWaitIdle failed: %d\\n\", result);\n        return false;\n    }\n\n    for (i = 0; i < demo->swap_chain_images_len; i++) {\n        vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);\n        vkDestroyImageView(demo->device, demo->overlay_image_views[i], NULL);\n        vkDestroyImage(demo->device, demo->overlay_images[i], NULL);\n        vkFreeMemory(demo->device, demo->overlay_image_memories[i], NULL);\n        vkDestroyImageView(demo->device, demo->swap_chain_image_views[i], NULL);\n    }\n    vkDestroySwapchainKHR(demo->device, demo->swap_chain, NULL);\n    vkDestroyRenderPass(demo->device, demo->render_pass, NULL);\n    vkDestroyPipeline(demo->device, demo->pipeline, NULL);\n    vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);\n    return true;\n}\n\nbool create_demo_texture(struct vulkan_demo *demo) {\n    VkResult result;\n    VkMemoryRequirements mem_requirements;\n    VkPhysicalDeviceMemoryProperties mem_properties;\n    int found;\n    uint32_t i;\n    VkImageCreateInfo image_info;\n    VkMemoryAllocateInfo alloc_info;\n    VkImageViewCreateInfo image_view_info;\n    VkBufferCreateInfo buffer_info;\n    struct {\n        VkDeviceMemory memory;\n        VkBuffer buffer;\n    } staging_buffer;\n    void *data;\n    VkCommandBuffer command_buffer;\n    VkCommandBufferBeginInfo begin_info;\n    VkImageMemoryBarrier image_transfer_dst_memory_barrier;\n    VkBufferImageCopy buffer_copy_region;\n    VkImageMemoryBarrier image_shader_memory_barrier;\n    VkFence fence;\n    VkFenceCreateInfo fence_create;\n    VkSubmitInfo submit_info;\n\n    memset(&image_info, 0, sizeof(VkImageCreateInfo));\n    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n    image_info.imageType = VK_IMAGE_TYPE_2D;\n    image_info.extent.width = 2;\n    image_info.extent.height = 2;\n    image_info.extent.depth = 1;\n    image_info.mipLevels = 1;\n    image_info.arrayLayers = 1;\n    image_info.format = VK_FORMAT_R8_UNORM;\n    image_info.tiling = VK_IMAGE_TILING_LINEAR;\n    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    image_info.usage =\n        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;\n    image_info.samples = VK_SAMPLE_COUNT_1_BIT;\n    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n\n    memset(&image_view_info, 0, sizeof(VkImageViewCreateInfo));\n    image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n    image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n    image_view_info.format = VK_FORMAT_R8_UNORM;\n    image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    image_view_info.subresourceRange.baseMipLevel = 0;\n    image_view_info.subresourceRange.levelCount = 1;\n    image_view_info.subresourceRange.baseArrayLayer = 0;\n    image_view_info.subresourceRange.layerCount = 1;\n\n    result = vkCreateImage(demo->device, &image_info, NULL,\n                           &demo->demo_texture_image);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateImage failed: %d\\n\", result);\n        return false;\n    }\n\n    vkGetImageMemoryRequirements(demo->device, demo->demo_texture_image,\n                                 &mem_requirements);\n\n    alloc_info.allocationSize = mem_requirements.size;\n\n    vkGetPhysicalDeviceMemoryProperties(demo->physical_device, &mem_properties);\n    found = 0;\n    for (i = 0; i < mem_properties.memoryTypeCount; i++) {\n        if ((mem_requirements.memoryTypeBits & (1 << i)) &&\n            (mem_properties.memoryTypes[i].propertyFlags &\n             VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ==\n                VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {\n            found = 1;\n            break;\n        }\n    }\n    if (!found) {\n        fprintf(stderr, \"failed to find suitable memory for demo texture!\\n\");\n        return false;\n    }\n    alloc_info.memoryTypeIndex = i;\n    result = vkAllocateMemory(demo->device, &alloc_info, NULL,\n                              &demo->demo_texture_memory);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr,\n                \"failed to allocate vulkan memory for demo texture: %d!\\n\",\n                result);\n        return false;\n    }\n    result = vkBindImageMemory(demo->device, demo->demo_texture_image,\n                               demo->demo_texture_memory, 0);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"Couldn't bind image memory for demo texture: %d\\n\",\n                result);\n        return false;\n    }\n\n    image_view_info.image = demo->demo_texture_image;\n    result = vkCreateImageView(demo->device, &image_view_info, NULL,\n                               &demo->demo_texture_image_view);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateImageView failed for demo texture: %d\\n\",\n                result);\n        return false;\n    }\n\n    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));\n    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n    buffer_info.size = alloc_info.allocationSize;\n    buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;\n    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    result = vkCreateBuffer(demo->device, &buffer_info, NULL,\n                            &staging_buffer.buffer);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateBuffer failed for demo texture: %d\\n\", result);\n        return false;\n    }\n    vkGetBufferMemoryRequirements(demo->device, staging_buffer.buffer,\n                                  &mem_requirements);\n\n    alloc_info.allocationSize = mem_requirements.size;\n    found = 0;\n    for (i = 0; i < mem_properties.memoryTypeCount; i++) {\n        if ((mem_requirements.memoryTypeBits & (1 << i)) &&\n            (mem_properties.memoryTypes[i].propertyFlags &\n             (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n              VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) ==\n                (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n                 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {\n            found = 1;\n            break;\n        }\n    }\n    if (!found) {\n        fprintf(stderr, \"failed to find suitable staging buffer memory for \"\n                        \"demo texture!\\n\");\n        return false;\n    }\n    alloc_info.memoryTypeIndex = i;\n    result = vkAllocateMemory(demo->device, &alloc_info, NULL,\n                              &staging_buffer.memory);\n    if (!found) {\n        fprintf(stderr, \"vkAllocateMemory failed for demo texture: %d\\n\",\n                result);\n        return false;\n    }\n    result = vkBindBufferMemory(demo->device, staging_buffer.buffer,\n                                staging_buffer.memory, 0);\n    if (!found) {\n        fprintf(stderr, \"vkBindBufferMemory failed for demo texture: %d\\n\",\n                result);\n        return false;\n    }\n\n    result = vkMapMemory(demo->device, staging_buffer.memory, 0,\n                         sizeof(uint32_t), 0, &data);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkMapMemory failed for demo texture: %d\\n\", result);\n        return false;\n    }\n    *((uint32_t *)data) = 0x00FFFF00;\n    vkUnmapMemory(demo->device, staging_buffer.memory);\n\n    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));\n    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n    command_buffer = demo->command_buffers[0];\n    result = vkBeginCommandBuffer(command_buffer, &begin_info);\n\n    memset(&image_transfer_dst_memory_barrier, 0, sizeof(VkImageMemoryBarrier));\n    image_transfer_dst_memory_barrier.sType =\n        VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n    image_transfer_dst_memory_barrier.image = demo->demo_texture_image;\n    image_transfer_dst_memory_barrier.srcQueueFamilyIndex =\n        VK_QUEUE_FAMILY_IGNORED;\n    image_transfer_dst_memory_barrier.dstQueueFamilyIndex =\n        VK_QUEUE_FAMILY_IGNORED;\n    image_transfer_dst_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    image_transfer_dst_memory_barrier.newLayout =\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n    image_transfer_dst_memory_barrier.subresourceRange.aspectMask =\n        VK_IMAGE_ASPECT_COLOR_BIT;\n    image_transfer_dst_memory_barrier.subresourceRange.levelCount = 1;\n    image_transfer_dst_memory_barrier.subresourceRange.layerCount = 1;\n    image_transfer_dst_memory_barrier.dstAccessMask =\n        VK_ACCESS_TRANSFER_WRITE_BIT;\n\n    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\n                         VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,\n                         &image_transfer_dst_memory_barrier);\n\n    memset(&buffer_copy_region, 0, sizeof(VkBufferImageCopy));\n    buffer_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    buffer_copy_region.imageSubresource.layerCount = 1;\n    buffer_copy_region.imageExtent.width = 2;\n    buffer_copy_region.imageExtent.height = 2;\n    buffer_copy_region.imageExtent.depth = 1;\n\n    vkCmdCopyBufferToImage(\n        command_buffer, staging_buffer.buffer, demo->demo_texture_image,\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_copy_region);\n\n    memset(&image_shader_memory_barrier, 0, sizeof(VkImageMemoryBarrier));\n    image_shader_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n    image_shader_memory_barrier.image = demo->demo_texture_image;\n    image_shader_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_shader_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_shader_memory_barrier.oldLayout =\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n    image_shader_memory_barrier.newLayout =\n        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n    image_shader_memory_barrier.subresourceRange.aspectMask =\n        VK_IMAGE_ASPECT_COLOR_BIT;\n    image_shader_memory_barrier.subresourceRange.levelCount = 1;\n    image_shader_memory_barrier.subresourceRange.layerCount = 1;\n    image_shader_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,\n    image_shader_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,\n\n    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,\n                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0,\n                         NULL, 1, &image_shader_memory_barrier);\n\n    result = vkEndCommandBuffer(command_buffer);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEndCommandBuffer failed for demo texture: %d\\n\",\n                result);\n        return false;\n    }\n\n    memset(&fence_create, 0, sizeof(VkFenceCreateInfo));\n    fence_create.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;\n    result = vkCreateFence(demo->device, &fence_create, NULL, &fence);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateFence failed for demo texture: %d\\n\", result);\n        return false;\n    }\n\n    memset(&submit_info, 0, sizeof(VkSubmitInfo));\n    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n    submit_info.commandBufferCount = 1;\n    submit_info.pCommandBuffers = &command_buffer;\n\n    result = vkQueueSubmit(demo->graphics_queue, 1, &submit_info, fence);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkQueueSubmit failed for demo texture: %d\\n\", result);\n        return false;\n    }\n    result = vkWaitForFences(demo->device, 1, &fence, VK_TRUE, UINT64_MAX);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkWaitForFences failed for demo texture: %d\\n\",\n                result);\n        return false;\n    }\n\n    vkDestroyBuffer(demo->device, staging_buffer.buffer, NULL);\n    vkFreeMemory(demo->device, staging_buffer.memory, NULL);\n    vkDestroyFence(demo->device, fence, NULL);\n\n    return true;\n}\n\nbool create_vulkan_demo(struct vulkan_demo *demo) {\n    if (!create_instance(demo)) {\n        return false;\n    }\n    if (!create_surface(demo)) {\n        return false;\n    }\n    if (!create_physical_device(demo)) {\n        return false;\n    }\n    if (!create_logical_device(demo)) {\n        return false;\n    }\n    if (!create_sampler(demo)) {\n        return false;\n    }\n    if (!create_descriptor_set_layout(demo)) {\n        return false;\n    }\n    if (!create_swap_chain_related_resources(demo)) {\n        return false;\n    }\n    if (!create_descriptor_pool(demo)) {\n        return false;\n    }\n    if (!create_descriptor_sets(demo)) {\n        return false;\n    }\n    if (!create_command_pool(demo)) {\n        return false;\n    }\n    if (!create_command_buffers(demo)) {\n        return false;\n    }\n    if (!create_semaphores(demo)) {\n        return false;\n    }\n    if (!create_fence(demo)) {\n        return false;\n    }\n    if (!create_demo_texture(demo)) {\n        return false;\n    }\n\n    demo->framebuffer_resized = false;\n\n    return true;\n}\n\nbool recreate_swap_chain(struct vulkan_demo *demo) {\n    printf(\"recreating swapchain\\n\");\n    if (!destroy_swap_chain_related_resources(demo)) {\n        return false;\n    }\n    if (!create_swap_chain_related_resources(demo)) {\n        return false;\n    }\n    update_descriptor_sets(demo);\n    nk_glfw3_resize(demo->swap_chain_image_extent.width,\n                    demo->swap_chain_image_extent.height);\n\n    demo->framebuffer_resized = false;\n\n    return true;\n}\n\nbool render(struct vulkan_demo *demo, struct nk_colorf *bg,\n            VkSemaphore wait_semaphore, uint32_t image_index) {\n    VkCommandBufferBeginInfo command_buffer_begin_info;\n    VkCommandBuffer command_buffer;\n    VkRenderPassBeginInfo render_pass_info;\n    VkSubmitInfo submit_info;\n    VkPipelineStageFlags wait_stage =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    VkResult result;\n    VkPresentInfoKHR present_info;\n    VkClearValue clear_color;\n\n    memcpy(&clear_color.color, bg, sizeof(VkClearColorValue));\n\n    memset(&command_buffer_begin_info, 0, sizeof(VkCommandBufferBeginInfo));\n    command_buffer_begin_info.sType =\n        VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n    command_buffer = demo->command_buffers[demo->current_in_flight_frame];\n    result = vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkBeginCommandBuffer failed: %d\\n\", result);\n        return false;\n    }\n\n    memset(&render_pass_info, 0, sizeof(VkRenderPassBeginInfo));\n    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;\n    render_pass_info.renderPass = demo->render_pass;\n    render_pass_info.framebuffer = demo->framebuffers[image_index];\n    render_pass_info.renderArea.offset.x = 0;\n    render_pass_info.renderArea.offset.y = 0;\n    render_pass_info.renderArea.extent = demo->swap_chain_image_extent;\n    render_pass_info.clearValueCount = 1;\n    render_pass_info.pClearValues = &clear_color;\n\n    vkCmdBeginRenderPass(command_buffer, &render_pass_info,\n                         VK_SUBPASS_CONTENTS_INLINE);\n\n    vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                      demo->pipeline);\n    vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                            demo->pipeline_layout, 0, 1,\n                            &demo->descriptor_sets[image_index], 0, NULL);\n    vkCmdDraw(command_buffer, 3, 1, 0, 0);\n\n    vkCmdEndRenderPass(command_buffer);\n\n    result = vkEndCommandBuffer(command_buffer);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEndCommandBuffer failed: %d\\n\", result);\n        return false;\n    }\n\n    memset(&submit_info, 0, sizeof(VkSubmitInfo));\n    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n    submit_info.waitSemaphoreCount = 1;\n    submit_info.pWaitSemaphores = &wait_semaphore;\n    submit_info.pWaitDstStageMask = &wait_stage;\n    submit_info.commandBufferCount = 1;\n    submit_info.pCommandBuffers = &command_buffer;\n    submit_info.signalSemaphoreCount = 1;\n    submit_info.pSignalSemaphores = &demo->render_finished[image_index];\n\n    result = vkQueueSubmit(demo->graphics_queue, 1, &submit_info,\n                           demo->render_fence[demo->current_in_flight_frame]);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkQueueSubmit failed: %d\\n\", result);\n        return false;\n    }\n\n    memset(&present_info, 0, sizeof(VkPresentInfoKHR));\n    present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;\n    present_info.waitSemaphoreCount = 1;\n    present_info.pWaitSemaphores = &demo->render_finished[image_index];\n    present_info.swapchainCount = 1;\n    present_info.pSwapchains = &demo->swap_chain;\n    present_info.pImageIndices = &image_index;\n\n    result = vkQueuePresentKHR(demo->present_queue, &present_info);\n\n    if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || demo->framebuffer_resized) {\n        if (!recreate_swap_chain(demo)) {\n            fprintf(stderr, \"failed to recreate swap chain!\\n\");\n        }\n    } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {\n        fprintf(stderr, \"vkQueuePresentKHR failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nVkResult\ndestroy_debug_utils_messenger_ext(VkInstance instance,\n                                  VkDebugUtilsMessengerEXT debugMessenger,\n                                  const VkAllocationCallbacks *pAllocator) {\n    PFN_vkDestroyDebugUtilsMessengerEXT func =\n        (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(\n            instance, \"vkDestroyDebugUtilsMessengerEXT\");\n    if (func != NULL) {\n        func(instance, debugMessenger, pAllocator);\n        return VK_SUCCESS;\n    } else {\n        return VK_ERROR_EXTENSION_NOT_PRESENT;\n    }\n}\n\nbool cleanup(struct vulkan_demo *demo) {\n    VkResult result;\n    uint32_t i;\n\n    printf(\"cleaning up\\n\");\n    result = vkDeviceWaitIdle(demo->device);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkDeviceWaitIdle failed: %d\\n\", result);\n        return false;\n    }\n\n    destroy_swap_chain_related_resources(demo);\n\n    vkFreeCommandBuffers(demo->device, demo->command_pool,\n                         MAX_IN_FLIGHT_FRAMES, demo->command_buffers);\n    vkDestroyCommandPool(demo->device, demo->command_pool, NULL);\n    vkDestroySampler(demo->device, demo->sampler, NULL);\n    \n    for(i = 0; i < demo->swap_chain_images_len; i++)\n     vkDestroySemaphore(demo->device, demo->render_finished[i], NULL);\n    if(demo->render_finished)\n     free(demo->render_finished);\n     \n    for(i = 0; i < MAX_IN_FLIGHT_FRAMES; i++)\n     vkDestroySemaphore(demo->device, demo->image_available[i], NULL);\n    if(demo->image_available)\n     free(demo->image_available);\n     \n    for(i = 0; i < MAX_IN_FLIGHT_FRAMES; i++)\n    vkDestroyFence(demo->device, demo->render_fence[i], NULL);\n    if(demo->render_fence)\n     free(demo->render_fence);\n    \n    vkDestroyImage(demo->device, demo->demo_texture_image, NULL);\n    vkDestroyImageView(demo->device, demo->demo_texture_image_view, NULL);\n    vkFreeMemory(demo->device, demo->demo_texture_memory, NULL);\n\n    vkDestroyDescriptorSetLayout(demo->device, demo->descriptor_set_layout,\n                                 NULL);\n    vkDestroyDescriptorPool(demo->device, demo->descriptor_pool, NULL);\n\n    vkDestroyDevice(demo->device, NULL);\n    vkDestroySurfaceKHR(demo->instance, demo->surface, NULL);\n\n    if (demo->debug_messenger) {\n        result = destroy_debug_utils_messenger_ext(demo->instance,\n                                                   demo->debug_messenger, NULL);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"Couldn't destroy debug messenger: %d\\n\", result);\n            return false;\n        }\n    }\n    vkDestroyInstance(demo->instance, NULL);\n    if (demo->swap_chain_images) {\n        free(demo->swap_chain_images);\n    }\n    if (demo->swap_chain_image_views) {\n        free(demo->swap_chain_image_views);\n    }\n\n    if (demo->overlay_images) {\n        free(demo->overlay_images);\n    }\n    if (demo->overlay_image_views) {\n        free(demo->overlay_image_views);\n    }\n    if (demo->overlay_image_memories) {\n        free(demo->overlay_image_memories);\n    }\n\n    if (demo->descriptor_sets) {\n        free(demo->descriptor_sets);\n    }\n    if (demo->framebuffers) {\n        free(demo->framebuffers);\n    }\n    if (demo->command_buffers) {\n        free(demo->command_buffers);\n    }\n\n    return true;\n}\n\nint main(void) {\n    struct vulkan_demo demo;\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n    struct nk_image img;\n    uint32_t image_index;\n    VkResult result;\n    VkSemaphore nk_semaphore;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    glfwSetErrorCallback(glfw_error_callback);\n    if (!glfwInit()) {\n        fprintf(stderr, \"[GFLW] failed to init!\\n\");\n        exit(1);\n    }\n    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);\n    memset(&demo, 0, sizeof(struct vulkan_demo));\n    demo.win =\n        glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, \"Demo\", NULL, NULL);\n    glfwSetWindowUserPointer(demo.win, &demo);\n    glfwSetFramebufferSizeCallback(demo.win, glfw_framebuffer_resize_callback);\n\n    if (!create_vulkan_demo(&demo)) {\n        fprintf(stderr, \"failed to create vulkan demo!\\n\");\n        exit(1);\n    }\n    ctx = nk_glfw3_init(\n        demo.win, demo.device, demo.physical_device, demo.indices.graphics,\n        demo.overlay_image_views, demo.swap_chain_images_len,\n        demo.swap_chain_image_format, NK_GLFW3_INSTALL_CALLBACKS,\n        MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {\n        struct nk_font_atlas *atlas;\n        nk_glfw3_font_stash_begin(&atlas);\n        /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas,\n         * \"../../../extra_font/DroidSans.ttf\", 14, 0);*/\n        /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas,\n         * \"../../../extra_font/Roboto-Regular.ttf\", 14, 0);*/\n        /*struct nk_font *future = nk_font_atlas_add_from_file(atlas,\n         * \"../../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n        /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas,\n         * \"../../../extra_font/ProggyClean.ttf\", 12, 0);*/\n        /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas,\n         * \"../../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n        /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas,\n         * \"../../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n        nk_glfw3_font_stash_end(demo.graphics_queue);\n        /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &droid->handle);*/}\n\n    img = nk_image_ptr(demo.demo_texture_image_view);\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (!glfwWindowShouldClose(demo.win)) {\n        /* Input */\n        glfwPollEvents();\n        nk_glfw3_new_frame();\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n                     NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE |\n                         NK_WINDOW_MINIMIZABLE | NK_WINDOW_TITLE)) {\n            enum { EASY, HARD };\n            static int op = EASY;\n            static int property = 20;\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY))\n                op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD))\n                op = HARD;\n\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg),\n                                     nk_vec2(nk_widget_width(ctx), 400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f, 0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f, 0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f, 0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f, 0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* Bindless Texture */\n        if (nk_begin(ctx, \"Texture\", nk_rect(500, 300, 200, 200),\n                     NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE |\n                         NK_WINDOW_MINIMIZABLE | NK_WINDOW_TITLE)) {\n            struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);\n            struct nk_rect total_space = nk_window_get_content_region(ctx);\n            nk_draw_image(canvas, total_space, &img, nk_white);\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n#ifdef INCLUDE_CALCULATOR\n        calculator(ctx);\n#endif\n#ifdef INCLUDE_CANVAS\n        canvas(ctx);\n#endif\n#ifdef INCLUDE_OVERVIEW\n        overview(ctx);\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n        style_configurator(ctx, color_table);\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n        node_editor(ctx);\n#endif\n        /* ----------------------------------------- */\n\n        result = vkWaitForFences(demo.device, 1, &demo.render_fence[demo.current_in_flight_frame], VK_TRUE,\n                                 UINT64_MAX);\n                                 \n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkWaitForFences failed: %d\\n\", result);\n            return false;\n        }\n\n        result = vkResetFences(demo.device, 1, &demo.render_fence[demo.current_in_flight_frame]);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkResetFences failed: %d\\n\", result);\n            return false;\n        }\n\n        result =\n            vkAcquireNextImageKHR(demo.device, demo.swap_chain, UINT64_MAX,\n                                  demo.image_available[demo.current_in_flight_frame], NULL, &image_index);\n\n        if (result == VK_ERROR_OUT_OF_DATE_KHR) {\n            recreate_swap_chain(&demo);\n\n            /* If vkAcquireNextImageKHR does not successfully acquire an image,\n             * semaphore and fence are unaffected. */\n            continue;\n        }\n        if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {\n            fprintf(stderr, \"vkAcquireNextImageKHR failed: %d\\n\", result);\n            return false;\n        }\n\n        /* Draw */\n        nk_semaphore =\n            nk_glfw3_render(demo.graphics_queue, image_index,\n                           demo.image_available[demo.current_in_flight_frame], NK_ANTI_ALIASING_ON);\n        if (!render(&demo, &bg, nk_semaphore, image_index)) {\n            fprintf(stderr, \"render failed\\n\");\n            return false;\n        }\n        demo.current_in_flight_frame = (demo.current_in_flight_frame + 1) % MAX_IN_FLIGHT_FRAMES;\n    }\n    nk_glfw3_shutdown();\n    cleanup(&demo);\n    glfwTerminate();\n    return 0;\n}\n"
  },
  {
    "path": "demo/glfw_vulkan/nuklear_glfw_vulkan.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_GLFW_VULKAN_H_\n#define NK_GLFW_VULKAN_H_\n\nunsigned char nuklearshaders_nuklear_vert_spv[] = {\n  0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x0d, 0x00,\n  0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,\n  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,\n  0x0a, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n  0x2a, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,\n  0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00,\n  0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73,\n  0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64,\n  0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00,\n  0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c,\n  0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f,\n  0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69,\n  0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47,\n  0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,\n  0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00,\n  0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,\n  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00,\n  0x67, 0x6c, 0x5f, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,\n  0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74,\n  0x69, 0x6f, 0x6e, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x00,\n  0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x42, 0x75, 0x66, 0x66, 0x65,\n  0x72, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x00, 0x06, 0x00, 0x06, 0x00,\n  0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x72, 0x6f, 0x6a,\n  0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,\n  0x10, 0x00, 0x00, 0x00, 0x75, 0x62, 0x6f, 0x00, 0x05, 0x00, 0x05, 0x00,\n  0x16, 0x00, 0x00, 0x00, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,\n  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00,\n  0x66, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00,\n  0x05, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f,\n  0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00,\n  0x66, 0x72, 0x61, 0x67, 0x55, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,\n  0x43, 0x00, 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,\n  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00,\n  0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,\n  0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n  0x47, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n  0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,\n  0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,\n  0x16, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x47, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00,\n  0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,\n  0x42, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x47, 0x00, 0x04, 0x00, 0x43, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,\n  0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n  0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00,\n  0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,\n  0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,\n  0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n  0x15, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,\n  0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00,\n  0x0d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n  0x1e, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,\n  0x20, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n  0x0e, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00,\n  0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,\n  0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,\n  0x17, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,\n  0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x20, 0x00, 0x04, 0x00,\n  0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n  0x15, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,\n  0x22, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n  0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00,\n  0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,\n  0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,\n  0x3b, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,\n  0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x7f, 0x43, 0x2b, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x36, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,\n  0x20, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n  0x20, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n  0x14, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00,\n  0x42, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,\n  0x15, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,\n  0x05, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00,\n  0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,\n  0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n  0x12, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,\n  0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x1b, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,\n  0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n  0x19, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,\n  0x1d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,\n  0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,\n  0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,\n  0x1f, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,\n  0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,\n  0x0c, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n  0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,\n  0x24, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x22, 0x00, 0x00, 0x00,\n  0x26, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,\n  0x21, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00,\n  0x25, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00,\n  0x2d, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00,\n  0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,\n  0x2d, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x2f, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00,\n  0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00,\n  0x32, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n  0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,\n  0x32, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x34, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n  0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00,\n  0x37, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n  0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,\n  0x37, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x39, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,\n  0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00,\n  0x3c, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00,\n  0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00,\n  0x3c, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x3e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,\n  0x30, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,\n  0x40, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,\n  0x3a, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,\n  0x27, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,\n  0x14, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,\n  0x3e, 0x00, 0x03, 0x00, 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,\n  0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00\n};\nunsigned int nuklearshaders_nuklear_vert_spv_len = 1856;\nunsigned char nuklearshaders_nuklear_frag_spv[] = {\n  0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x0d, 0x00,\n  0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,\n  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00,\n  0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,\n  0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n  0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n  0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00,\n  0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73,\n  0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64,\n  0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00,\n  0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c,\n  0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f,\n  0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69,\n  0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47,\n  0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,\n  0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00,\n  0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,\n  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00,\n  0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00,\n  0x05, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x63, 0x75, 0x72, 0x72,\n  0x65, 0x6e, 0x74, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x00,\n  0x05, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67,\n  0x55, 0x76, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00,\n  0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00,\n  0x05, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67,\n  0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,\n  0x0d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,\n  0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,\n  0x15, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x47, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,\n  0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n  0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,\n  0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00,\n  0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00,\n  0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,\n  0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,\n  0x3b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,\n  0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,\n  0x3b, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,\n  0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,\n  0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n  0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00,\n  0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,\n  0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,\n  0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n  0x07, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,\n  0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,\n  0x0f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n  0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n  0x0e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,\n  0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,\n  0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n  0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n  0x09, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,\n  0x1a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n  0x3e, 0x00, 0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,\n  0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00\n};\nunsigned int nuklearshaders_nuklear_frag_spv_len = 860;\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n#define GLFW_INCLUDE_VULKAN\n#include <GLFW/glfw3.h>\n\nenum nk_glfw_init_state { NK_GLFW3_DEFAULT = 0, NK_GLFW3_INSTALL_CALLBACKS };\n\nNK_API struct nk_context *\nnk_glfw3_init(GLFWwindow *win, VkDevice logical_device,\n              VkPhysicalDevice physical_device,\n              uint32_t graphics_queue_family_index, VkImageView *image_views,\n              uint32_t image_views_len, VkFormat color_format,\n              enum nk_glfw_init_state init_state,\n              VkDeviceSize max_vertex_buffer, VkDeviceSize max_element_buffer);\nNK_API void nk_glfw3_shutdown(void);\nNK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void nk_glfw3_font_stash_end(VkQueue graphics_queue);\nNK_API void nk_glfw3_new_frame();\nNK_API VkSemaphore nk_glfw3_render(VkQueue graphics_queue,\n                                   uint32_t buffer_index,\n                                   VkSemaphore wait_semaphore,\n                                   enum nk_anti_aliasing AA);\nNK_API void nk_glfw3_resize(uint32_t framebuffer_width,\n                            uint32_t framebuffer_height);\nNK_API void nk_glfw3_device_destroy(void);\nNK_API void nk_glfw3_device_create(\n    VkDevice logical_device, VkPhysicalDevice physical_device,\n    uint32_t graphics_queue_family_index, VkImageView *image_views,\n    uint32_t image_views_len, VkFormat color_format,\n    VkDeviceSize max_vertex_buffer, VkDeviceSize max_element_buffer,\n    uint32_t framebuffer_width, uint32_t framebuffer_height);\n\nNK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);\nNK_API void nk_glfw3_key_callback(GLFWwindow *win, int key, int scancode, int action, int mods);\nNK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);\nNK_API void nk_glfw3_mouse_button_callback(GLFWwindow *win, int button,\n                                           int action, int mods);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_GLFW_VULKAN_IMPLEMENTATION\n#undef NK_GLFW_VULKAN_IMPLEMENTATION\n#include <stdlib.h>\n\n#ifndef NK_GLFW_TEXT_MAX\n#define NK_GLFW_TEXT_MAX 256\n#endif\n#ifndef NK_GLFW_DOUBLE_CLICK_LO\n#define NK_GLFW_DOUBLE_CLICK_LO 0.02\n#endif\n#ifndef NK_GLFW_DOUBLE_CLICK_HI\n#define NK_GLFW_DOUBLE_CLICK_HI 0.2\n#endif\n#ifndef NK_GLFW_MAX_TEXTURES\n#define NK_GLFW_MAX_TEXTURES 256\n#endif\n\n#define VK_COLOR_COMPONENT_MASK_RGBA                                           \\\n    VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |                      \\\n        VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT\n\nstruct nk_glfw_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstruct nk_vulkan_texture_descriptor_set {\n    VkImageView image_view;\n    VkDescriptorSet descriptor_set;\n};\n\nstruct nk_glfw_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    int max_vertex_buffer;\n    int max_element_buffer;\n    VkDevice logical_device;\n    VkPhysicalDevice physical_device;\n    VkImageView *image_views;\n    uint32_t image_views_len;\n    VkFormat color_format;\n    VkFramebuffer *framebuffers;\n    uint32_t framebuffers_len;\n    VkCommandBuffer *command_buffers;\n    uint32_t command_buffers_len;\n    VkSampler sampler;\n    VkCommandPool command_pool;\n    VkSemaphore render_completed;\n    VkBuffer vertex_buffer;\n    VkDeviceMemory vertex_memory;\n    void *mapped_vertex;\n    VkBuffer index_buffer;\n    VkDeviceMemory index_memory;\n    void *mapped_index;\n    VkBuffer uniform_buffer;\n    VkDeviceMemory uniform_memory;\n    void *mapped_uniform;\n    VkRenderPass render_pass;\n    VkDescriptorPool descriptor_pool;\n    VkDescriptorSetLayout uniform_descriptor_set_layout;\n    VkDescriptorSet uniform_descriptor_set;\n    VkDescriptorSetLayout texture_descriptor_set_layout;\n    struct nk_vulkan_texture_descriptor_set *texture_descriptor_sets;\n    uint32_t texture_descriptor_sets_len;\n    VkPipelineLayout pipeline_layout;\n    VkPipeline pipeline;\n    VkImage font_image;\n    VkImageView font_image_view;\n    VkDeviceMemory font_memory;\n};\n\nstatic struct nk_glfw {\n    GLFWwindow *win;\n    int width, height;\n    int display_width, display_height;\n    struct nk_glfw_device vulkan;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    struct nk_vec2 fb_scale;\n    unsigned int text[NK_GLFW_TEXT_MAX];\n    nk_char key_events[NK_KEY_MAX];\n    int text_len;\n    struct nk_vec2 scroll;\n    double last_button_click;\n    int is_double_click_down;\n    struct nk_vec2 double_click_pos;\n    float delta_time_seconds_last;\n} glfw;\n\nstruct Mat4f {\n    float m[16];\n};\n\nNK_INTERN uint32_t nk_glfw3_find_memory_index(\n    VkPhysicalDevice physical_device, uint32_t type_filter,\n    VkMemoryPropertyFlags properties) {\n    VkPhysicalDeviceMemoryProperties mem_properties;\n    uint32_t i;\n\n    vkGetPhysicalDeviceMemoryProperties(physical_device, &mem_properties);\n    for (i = 0; i < mem_properties.memoryTypeCount; i++) {\n        if ((type_filter & (1 << i)) &&\n            (mem_properties.memoryTypes[i].propertyFlags & properties) ==\n                properties) {\n            return i;\n        }\n    }\n\n    assert(0);\n    return 0;\n}\n\nNK_INTERN void nk_glfw3_create_sampler(struct nk_glfw_device *dev) {\n    VkResult result;\n    VkSamplerCreateInfo sampler_info;\n    memset(&sampler_info, 0, sizeof(VkSamplerCreateInfo));\n\n    sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n    sampler_info.pNext = NULL;\n    sampler_info.maxAnisotropy = 1.0;\n    sampler_info.magFilter = VK_FILTER_LINEAR;\n    sampler_info.minFilter = VK_FILTER_LINEAR;\n    sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n    sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.mipLodBias = 0.0f;\n    sampler_info.compareEnable = VK_FALSE;\n    sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;\n    sampler_info.minLod = 0.0f;\n    sampler_info.maxLod = 0.0f;\n    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;\n\n    result = vkCreateSampler(dev->logical_device, &sampler_info, NULL,\n                             &dev->sampler);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_glfw3_create_command_pool(struct nk_glfw_device *dev,\n                             uint32_t graphics_queue_family_index) {\n    VkResult result;\n    VkCommandPoolCreateInfo pool_info;\n    memset(&pool_info, 0, sizeof(VkCommandPoolCreateInfo));\n\n    pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;\n    pool_info.queueFamilyIndex = graphics_queue_family_index;\n    pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;\n    result = vkCreateCommandPool(dev->logical_device, &pool_info, NULL,\n                                 &dev->command_pool);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_glfw3_create_command_buffers(struct nk_glfw_device *dev) {\n    VkResult result;\n    VkCommandBufferAllocateInfo allocate_info;\n    memset(&allocate_info, 0, sizeof(VkCommandBufferAllocateInfo));\n\n    dev->command_buffers = (VkCommandBuffer *)malloc(dev->image_views_len *\n                                                     sizeof(VkCommandBuffer));\n    dev->command_buffers_len = dev->image_views_len;\n\n    allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;\n    allocate_info.commandPool = dev->command_pool;\n    allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;\n    allocate_info.commandBufferCount = dev->command_buffers_len;\n\n    result = vkAllocateCommandBuffers(dev->logical_device, &allocate_info,\n                                      dev->command_buffers);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_glfw3_create_semaphore(struct nk_glfw_device *dev) {\n    VkResult result;\n    VkSemaphoreCreateInfo semaphore_info;\n    memset(&semaphore_info, 0, sizeof(VkSemaphoreCreateInfo));\n\n    semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;\n    result = (vkCreateSemaphore(dev->logical_device, &semaphore_info, NULL,\n                                &dev->render_completed));\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_glfw3_create_buffer_and_memory(struct nk_glfw_device *dev,\n                                                 VkBuffer *buffer,\n                                                 VkBufferUsageFlags usage,\n                                                 VkDeviceMemory *memory,\n                                                 VkDeviceSize size) {\n    VkMemoryRequirements mem_reqs;\n    VkResult result;\n    VkBufferCreateInfo buffer_info;\n    VkMemoryAllocateInfo alloc_info;\n\n    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));\n    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n    buffer_info.size = size;\n    buffer_info.usage = usage;\n    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    result = vkCreateBuffer(dev->logical_device, &buffer_info, NULL, buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkGetBufferMemoryRequirements(dev->logical_device, *buffer, &mem_reqs);\n\n    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n    alloc_info.allocationSize = mem_reqs.size;\n    alloc_info.memoryTypeIndex = nk_glfw3_find_memory_index(\n        dev->physical_device, mem_reqs.memoryTypeBits,\n        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n            VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\n    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL, memory);\n    NK_ASSERT(result == VK_SUCCESS);\n    result = vkBindBufferMemory(dev->logical_device, *buffer, *memory, 0);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_glfw3_create_render_pass(struct nk_glfw_device *dev) {\n    VkAttachmentDescription attachment;\n    VkAttachmentReference color_reference;\n    VkSubpassDependency subpass_dependency;\n    VkSubpassDescription subpass_description;\n    VkRenderPassCreateInfo render_pass_info;\n    VkResult result;\n\n    memset(&attachment, 0, sizeof(VkAttachmentDescription));\n    attachment.format = dev->color_format;\n    attachment.samples = VK_SAMPLE_COUNT_1_BIT;\n    attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;\n    attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n    attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n    attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n    attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    attachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n\n    memset(&color_reference, 0, sizeof(VkAttachmentReference));\n    color_reference.attachment = 0;\n    color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;\n\n    memset(&subpass_dependency, 0, sizeof(VkSubpassDependency));\n    subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;\n    subpass_dependency.srcAccessMask = 0;\n    subpass_dependency.srcStageMask =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    subpass_dependency.dstSubpass = 0;\n    subpass_dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |\n                                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n    subpass_dependency.dstStageMask =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n\n    memset(&subpass_description, 0, sizeof(VkSubpassDescription));\n    subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;\n    subpass_description.colorAttachmentCount = 1;\n    subpass_description.pColorAttachments = &color_reference;\n\n    memset(&render_pass_info, 0, sizeof(VkRenderPassCreateInfo));\n    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;\n    render_pass_info.attachmentCount = 1;\n    render_pass_info.pAttachments = &attachment;\n    render_pass_info.subpassCount = 1;\n    render_pass_info.pSubpasses = &subpass_description;\n    render_pass_info.dependencyCount = 1;\n    render_pass_info.pDependencies = &subpass_dependency;\n\n    result = vkCreateRenderPass(dev->logical_device, &render_pass_info, NULL,\n                                &dev->render_pass);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_glfw3_create_framebuffers(struct nk_glfw_device *dev,\n                                            uint32_t framebuffer_width,\n                                            uint32_t framebuffer_height) {\n\n    VkFramebufferCreateInfo framebuffer_create_info;\n    uint32_t i;\n    VkResult result;\n\n    dev->framebuffers =\n        (VkFramebuffer *)malloc(dev->image_views_len * sizeof(VkFramebuffer));\n\n    memset(&framebuffer_create_info, 0, sizeof(VkFramebufferCreateInfo));\n    framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;\n    framebuffer_create_info.renderPass = dev->render_pass;\n    framebuffer_create_info.attachmentCount = 1;\n    framebuffer_create_info.width = framebuffer_width;\n    framebuffer_create_info.height = framebuffer_height;\n    framebuffer_create_info.layers = 1;\n    for (i = 0; i < dev->image_views_len; i++) {\n        framebuffer_create_info.pAttachments = &dev->image_views[i];\n        result =\n            vkCreateFramebuffer(dev->logical_device, &framebuffer_create_info,\n                                NULL, &dev->framebuffers[i]);\n        NK_ASSERT(result == VK_SUCCESS);\n    }\n    dev->framebuffers_len = dev->image_views_len;\n}\n\nNK_INTERN void nk_glfw3_create_descriptor_pool(struct nk_glfw_device *dev) {\n    VkDescriptorPoolSize pool_sizes[2];\n    VkDescriptorPoolCreateInfo pool_info;\n    VkResult result;\n\n    memset(&pool_sizes, 0, sizeof(VkDescriptorPoolSize) * 2);\n    pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n    pool_sizes[0].descriptorCount = 1;\n    pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    pool_sizes[1].descriptorCount = NK_GLFW_MAX_TEXTURES;\n\n    memset(&pool_info, 0, sizeof(VkDescriptorPoolCreateInfo));\n    pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;\n    pool_info.poolSizeCount = 2;\n    pool_info.pPoolSizes = pool_sizes;\n    pool_info.maxSets = 1 + NK_GLFW_MAX_TEXTURES;\n\n    result = vkCreateDescriptorPool(dev->logical_device, &pool_info, NULL,\n                                    &dev->descriptor_pool);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_glfw3_create_uniform_descriptor_set_layout(struct nk_glfw_device *dev) {\n    VkDescriptorSetLayoutBinding binding;\n    VkDescriptorSetLayoutCreateInfo descriptor_set_info;\n    VkResult result;\n\n    memset(&binding, 0, sizeof(VkDescriptorSetLayoutBinding));\n    binding.binding = 0;\n    binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n    binding.descriptorCount = 1;\n    binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;\n\n    memset(&descriptor_set_info, 0, sizeof(VkDescriptorSetLayoutCreateInfo));\n    descriptor_set_info.sType =\n        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n    descriptor_set_info.bindingCount = 1;\n    descriptor_set_info.pBindings = &binding;\n\n    result =\n        vkCreateDescriptorSetLayout(dev->logical_device, &descriptor_set_info,\n                                    NULL, &dev->uniform_descriptor_set_layout);\n\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_glfw3_create_and_update_uniform_descriptor_set(struct nk_glfw_device *dev) {\n    VkDescriptorSetAllocateInfo allocate_info;\n    VkDescriptorBufferInfo buffer_info;\n    VkWriteDescriptorSet descriptor_write;\n    VkResult result;\n\n    memset(&allocate_info, 0, sizeof(VkDescriptorSetAllocateInfo));\n    allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n    allocate_info.descriptorPool = dev->descriptor_pool;\n    allocate_info.descriptorSetCount = 1;\n    allocate_info.pSetLayouts = &dev->uniform_descriptor_set_layout;\n\n    result = vkAllocateDescriptorSets(dev->logical_device, &allocate_info,\n                                      &dev->uniform_descriptor_set);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&buffer_info, 0, sizeof(VkDescriptorBufferInfo));\n    buffer_info.buffer = dev->uniform_buffer;\n    buffer_info.offset = 0;\n    buffer_info.range = sizeof(struct Mat4f);\n\n    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));\n    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n    descriptor_write.dstSet = dev->uniform_descriptor_set;\n    descriptor_write.dstBinding = 0;\n    descriptor_write.dstArrayElement = 0;\n    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n    descriptor_write.descriptorCount = 1;\n    descriptor_write.pBufferInfo = &buffer_info;\n\n    vkUpdateDescriptorSets(dev->logical_device, 1, &descriptor_write, 0, NULL);\n}\n\nNK_INTERN void\nnk_glfw3_create_texture_descriptor_set_layout(struct nk_glfw_device *dev) {\n    VkDescriptorSetLayoutBinding binding;\n    VkDescriptorSetLayoutCreateInfo descriptor_set_info;\n    VkResult result;\n\n    memset(&binding, 0, sizeof(VkDescriptorSetLayoutBinding));\n    binding.binding = 0;\n    binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    binding.descriptorCount = 1;\n    binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;\n\n    memset(&descriptor_set_info, 0, sizeof(VkDescriptorSetLayoutCreateInfo));\n    descriptor_set_info.sType =\n        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n    descriptor_set_info.bindingCount = 1;\n    descriptor_set_info.pBindings = &binding;\n\n    result =\n        vkCreateDescriptorSetLayout(dev->logical_device, &descriptor_set_info,\n                                    NULL, &dev->texture_descriptor_set_layout);\n\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_glfw3_create_texture_descriptor_sets(struct nk_glfw_device *dev) {\n    VkDescriptorSetLayout *descriptor_set_layouts;\n    VkDescriptorSet *descriptor_sets;\n    VkDescriptorSetAllocateInfo allocate_info;\n    VkResult result;\n    int i;\n\n    descriptor_set_layouts = (VkDescriptorSetLayout *)malloc(\n        NK_GLFW_MAX_TEXTURES * sizeof(VkDescriptorSetLayout));\n    descriptor_sets = (VkDescriptorSet *)malloc(NK_GLFW_MAX_TEXTURES *\n                                                sizeof(VkDescriptorSet));\n\n    dev->texture_descriptor_sets =\n        (struct nk_vulkan_texture_descriptor_set *)malloc(\n            NK_GLFW_MAX_TEXTURES *\n            sizeof(struct nk_vulkan_texture_descriptor_set));\n    dev->texture_descriptor_sets_len = 0;\n\n    for (i = 0; i < NK_GLFW_MAX_TEXTURES; i++) {\n        descriptor_set_layouts[i] = dev->texture_descriptor_set_layout;\n        descriptor_sets[i] = dev->texture_descriptor_sets[i].descriptor_set;\n    }\n\n    memset(&allocate_info, 0, sizeof(VkDescriptorSetAllocateInfo));\n    allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n    allocate_info.descriptorPool = dev->descriptor_pool;\n    allocate_info.descriptorSetCount = NK_GLFW_MAX_TEXTURES;\n    allocate_info.pSetLayouts = descriptor_set_layouts;\n\n    result = vkAllocateDescriptorSets(dev->logical_device, &allocate_info,\n                                      descriptor_sets);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    for (i = 0; i < NK_GLFW_MAX_TEXTURES; i++) {\n        dev->texture_descriptor_sets[i].descriptor_set = descriptor_sets[i];\n    }\n    free(descriptor_set_layouts);\n    free(descriptor_sets);\n}\n\nNK_INTERN void nk_glfw3_create_pipeline_layout(struct nk_glfw_device *dev) {\n    VkPipelineLayoutCreateInfo pipeline_layout_info;\n    VkDescriptorSetLayout descriptor_set_layouts[2];\n    VkResult result;\n\n    descriptor_set_layouts[0] = dev->uniform_descriptor_set_layout;\n    descriptor_set_layouts[1] = dev->texture_descriptor_set_layout;\n\n    memset(&pipeline_layout_info, 0, sizeof(VkPipelineLayoutCreateInfo));\n    pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;\n    pipeline_layout_info.setLayoutCount = 2;\n    pipeline_layout_info.pSetLayouts = descriptor_set_layouts;\n\n    result = (vkCreatePipelineLayout(dev->logical_device, &pipeline_layout_info,\n                                     NULL, &dev->pipeline_layout));\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN VkPipelineShaderStageCreateInfo\nnk_glfw3_create_shader(struct nk_glfw_device *dev, unsigned char *spv_shader,\n                       uint32_t size, VkShaderStageFlagBits stage_bit) {\n    VkShaderModuleCreateInfo create_info;\n    VkPipelineShaderStageCreateInfo shader_info;\n    VkShaderModule module = NULL;\n    VkResult result;\n\n    memset(&create_info, 0, sizeof(VkShaderModuleCreateInfo));\n    create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;\n    create_info.codeSize = size;\n    create_info.pCode = (const uint32_t *)spv_shader;\n    result =\n        vkCreateShaderModule(dev->logical_device, &create_info, NULL, &module);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&shader_info, 0, sizeof(VkPipelineShaderStageCreateInfo));\n    shader_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;\n    shader_info.stage = stage_bit;\n    shader_info.module = module;\n    shader_info.pName = \"main\";\n    return shader_info;\n}\n\nNK_INTERN void nk_glfw3_create_pipeline(struct nk_glfw_device *dev) {\n    VkPipelineInputAssemblyStateCreateInfo input_assembly_state;\n    VkPipelineRasterizationStateCreateInfo rasterization_state;\n    VkPipelineColorBlendAttachmentState attachment_state = {\n        VK_TRUE,\n        VK_BLEND_FACTOR_SRC_ALPHA,\n        VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,\n        VK_BLEND_OP_ADD,\n        VK_BLEND_FACTOR_SRC_ALPHA,\n        VK_BLEND_FACTOR_ONE,\n        VK_BLEND_OP_ADD,\n        VK_COLOR_COMPONENT_MASK_RGBA,\n    };\n    VkPipelineColorBlendStateCreateInfo color_blend_state;\n    VkPipelineViewportStateCreateInfo viewport_state;\n    VkPipelineMultisampleStateCreateInfo multisample_state;\n    VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT,\n                                        VK_DYNAMIC_STATE_SCISSOR};\n    VkPipelineDynamicStateCreateInfo dynamic_state;\n    VkPipelineShaderStageCreateInfo shader_stages[2];\n    VkVertexInputBindingDescription vertex_input_info;\n    VkVertexInputAttributeDescription vertex_attribute_description[3];\n    VkPipelineVertexInputStateCreateInfo vertex_input;\n    VkGraphicsPipelineCreateInfo pipeline_info;\n    VkResult result;\n\n    memset(&input_assembly_state, 0,\n           sizeof(VkPipelineInputAssemblyStateCreateInfo));\n    input_assembly_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;\n    input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;\n    input_assembly_state.primitiveRestartEnable = VK_FALSE;\n\n    memset(&rasterization_state, 0,\n           sizeof(VkPipelineRasterizationStateCreateInfo));\n    rasterization_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;\n    rasterization_state.polygonMode = VK_POLYGON_MODE_FILL;\n    rasterization_state.cullMode = VK_CULL_MODE_NONE;\n    rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;\n    rasterization_state.lineWidth = 1.0f;\n\n    memset(&color_blend_state, 0, sizeof(VkPipelineColorBlendStateCreateInfo));\n    color_blend_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;\n    color_blend_state.attachmentCount = 1;\n    color_blend_state.pAttachments = &attachment_state;\n\n    memset(&viewport_state, 0, sizeof(VkPipelineViewportStateCreateInfo));\n    viewport_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;\n    viewport_state.viewportCount = 1;\n    viewport_state.scissorCount = 1;\n\n    memset(&multisample_state, 0, sizeof(VkPipelineMultisampleStateCreateInfo));\n    multisample_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;\n    multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;\n\n    memset(&dynamic_state, 0, sizeof(VkPipelineDynamicStateCreateInfo));\n    dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;\n    dynamic_state.pDynamicStates = dynamic_states;\n    dynamic_state.dynamicStateCount = 2;\n\n    shader_stages[0] = nk_glfw3_create_shader(\n        dev, nuklearshaders_nuklear_vert_spv,\n        nuklearshaders_nuklear_vert_spv_len, VK_SHADER_STAGE_VERTEX_BIT);\n    shader_stages[1] = nk_glfw3_create_shader(\n        dev, nuklearshaders_nuklear_frag_spv,\n        nuklearshaders_nuklear_frag_spv_len, VK_SHADER_STAGE_FRAGMENT_BIT);\n\n    memset(&vertex_input_info, 0, sizeof(VkVertexInputBindingDescription));\n    vertex_input_info.binding = 0;\n    vertex_input_info.stride = sizeof(struct nk_glfw_vertex);\n    vertex_input_info.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;\n\n    memset(&vertex_attribute_description, 0,\n           sizeof(VkVertexInputAttributeDescription) * 3);\n    vertex_attribute_description[0].location = 0;\n    vertex_attribute_description[0].format = VK_FORMAT_R32G32_SFLOAT;\n    vertex_attribute_description[0].offset =\n        NK_OFFSETOF(struct nk_glfw_vertex, position);\n    vertex_attribute_description[1].location = 1;\n    vertex_attribute_description[1].format = VK_FORMAT_R32G32_SFLOAT;\n    vertex_attribute_description[1].offset =\n        NK_OFFSETOF(struct nk_glfw_vertex, uv);\n    vertex_attribute_description[2].location = 2;\n    vertex_attribute_description[2].format = VK_FORMAT_R8G8B8A8_UINT;\n    vertex_attribute_description[2].offset =\n        NK_OFFSETOF(struct nk_glfw_vertex, col);\n\n    memset(&vertex_input, 0, sizeof(VkPipelineVertexInputStateCreateInfo));\n    vertex_input.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;\n    vertex_input.vertexBindingDescriptionCount = 1;\n    vertex_input.pVertexBindingDescriptions = &vertex_input_info;\n    vertex_input.vertexAttributeDescriptionCount = 3;\n    vertex_input.pVertexAttributeDescriptions = vertex_attribute_description;\n\n    memset(&pipeline_info, 0, sizeof(VkGraphicsPipelineCreateInfo));\n    pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;\n    pipeline_info.flags = 0;\n    pipeline_info.stageCount = 2;\n    pipeline_info.pStages = shader_stages;\n    pipeline_info.pVertexInputState = &vertex_input;\n    pipeline_info.pInputAssemblyState = &input_assembly_state;\n    pipeline_info.pViewportState = &viewport_state;\n    pipeline_info.pRasterizationState = &rasterization_state;\n    pipeline_info.pMultisampleState = &multisample_state;\n    pipeline_info.pColorBlendState = &color_blend_state;\n    pipeline_info.pDynamicState = &dynamic_state;\n    pipeline_info.layout = dev->pipeline_layout;\n    pipeline_info.renderPass = dev->render_pass;\n    pipeline_info.basePipelineIndex = -1;\n    pipeline_info.basePipelineHandle = NULL;\n\n    result = vkCreateGraphicsPipelines(dev->logical_device, NULL, 1,\n                                       &pipeline_info, NULL, &dev->pipeline);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkDestroyShaderModule(dev->logical_device, shader_stages[0].module, NULL);\n    vkDestroyShaderModule(dev->logical_device, shader_stages[1].module, NULL);\n}\n\nNK_INTERN void nk_glfw3_create_render_resources(struct nk_glfw_device *dev,\n                                                uint32_t framebuffer_width,\n                                                uint32_t framebuffer_height) {\n    nk_glfw3_create_render_pass(dev);\n    nk_glfw3_create_framebuffers(dev, framebuffer_width, framebuffer_height);\n    nk_glfw3_create_descriptor_pool(dev);\n    nk_glfw3_create_uniform_descriptor_set_layout(dev);\n    nk_glfw3_create_and_update_uniform_descriptor_set(dev);\n    nk_glfw3_create_texture_descriptor_set_layout(dev);\n    nk_glfw3_create_texture_descriptor_sets(dev);\n    nk_glfw3_create_pipeline_layout(dev);\n    nk_glfw3_create_pipeline(dev);\n}\n\nNK_API void nk_glfw3_device_create(\n    VkDevice logical_device, VkPhysicalDevice physical_device,\n    uint32_t graphics_queue_family_index, VkImageView *image_views,\n    uint32_t image_views_len, VkFormat color_format,\n    VkDeviceSize max_vertex_buffer, VkDeviceSize max_element_buffer,\n    uint32_t framebuffer_width, uint32_t framebuffer_height) {\n    struct nk_glfw_device *dev = &glfw.vulkan;\n    dev->max_vertex_buffer = max_vertex_buffer;\n    dev->max_element_buffer = max_element_buffer;\n    nk_buffer_init_default(&dev->cmds);\n    dev->logical_device = logical_device;\n    dev->physical_device = physical_device;\n    dev->image_views = image_views;\n    dev->image_views_len = image_views_len;\n    dev->color_format = color_format;\n    dev->framebuffers = NULL;\n    dev->framebuffers_len = 0;\n\n    nk_glfw3_create_sampler(dev);\n    nk_glfw3_create_command_pool(dev, graphics_queue_family_index);\n    nk_glfw3_create_command_buffers(dev);\n    nk_glfw3_create_semaphore(dev);\n\n    nk_glfw3_create_buffer_and_memory(dev, &dev->vertex_buffer,\n                                      VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,\n                                      &dev->vertex_memory, max_vertex_buffer);\n    nk_glfw3_create_buffer_and_memory(dev, &dev->index_buffer,\n                                      VK_BUFFER_USAGE_INDEX_BUFFER_BIT,\n                                      &dev->index_memory, max_element_buffer);\n    nk_glfw3_create_buffer_and_memory(\n        dev, &dev->uniform_buffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,\n        &dev->uniform_memory, sizeof(struct Mat4f));\n\n    vkMapMemory(dev->logical_device, dev->vertex_memory, 0, max_vertex_buffer,\n                0, &dev->mapped_vertex);\n    vkMapMemory(dev->logical_device, dev->index_memory, 0, max_element_buffer,\n                0, &dev->mapped_index);\n    vkMapMemory(dev->logical_device, dev->uniform_memory, 0,\n                sizeof(struct Mat4f), 0, &dev->mapped_uniform);\n\n    nk_glfw3_create_render_resources(dev, framebuffer_width,\n                                     framebuffer_height);\n}\n\nNK_INTERN void nk_glfw3_device_upload_atlas(VkQueue graphics_queue,\n                                            const void *image, int width,\n                                            int height) {\n    struct nk_glfw_device *dev = &glfw.vulkan;\n\n    VkImageCreateInfo image_info;\n    VkResult result;\n    VkMemoryRequirements mem_reqs;\n    VkMemoryAllocateInfo alloc_info;\n    VkBufferCreateInfo buffer_info;\n    uint8_t *data = 0;\n    VkCommandBufferBeginInfo begin_info;\n    VkCommandBuffer command_buffer;\n    VkImageMemoryBarrier image_memory_barrier;\n    VkBufferImageCopy buffer_copy_region;\n    VkImageMemoryBarrier image_shader_memory_barrier;\n    VkFence fence;\n    VkFenceCreateInfo fence_create;\n    VkSubmitInfo submit_info;\n    VkImageViewCreateInfo image_view_info;\n    struct {\n        VkDeviceMemory memory;\n        VkBuffer buffer;\n    } staging_buffer;\n\n    memset(&image_info, 0, sizeof(VkImageCreateInfo));\n    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n    image_info.imageType = VK_IMAGE_TYPE_2D;\n    image_info.format = VK_FORMAT_R8G8B8A8_UNORM;\n    image_info.extent.width = (uint32_t)width;\n    image_info.extent.height = (uint32_t)height;\n    image_info.extent.depth = 1;\n    image_info.mipLevels = 1;\n    image_info.arrayLayers = 1;\n    image_info.samples = VK_SAMPLE_COUNT_1_BIT;\n    image_info.tiling = VK_IMAGE_TILING_OPTIMAL;\n    image_info.usage =\n        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;\n    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\n    result =\n        vkCreateImage(dev->logical_device, &image_info, NULL, &dev->font_image);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkGetImageMemoryRequirements(dev->logical_device, dev->font_image,\n                                 &mem_reqs);\n\n    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n    alloc_info.allocationSize = mem_reqs.size;\n    alloc_info.memoryTypeIndex = nk_glfw3_find_memory_index(\n        dev->physical_device, mem_reqs.memoryTypeBits,\n        VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);\n\n    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL,\n                              &dev->font_memory);\n    NK_ASSERT(result == VK_SUCCESS);\n    result = vkBindImageMemory(dev->logical_device, dev->font_image,\n                               dev->font_memory, 0);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));\n    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n    buffer_info.size = alloc_info.allocationSize;\n    buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;\n    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    result = vkCreateBuffer(dev->logical_device, &buffer_info, NULL,\n                            &staging_buffer.buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n    vkGetBufferMemoryRequirements(dev->logical_device, staging_buffer.buffer,\n                                  &mem_reqs);\n\n    alloc_info.allocationSize = mem_reqs.size;\n    alloc_info.memoryTypeIndex = nk_glfw3_find_memory_index(\n        dev->physical_device, mem_reqs.memoryTypeBits,\n        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n            VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\n    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL,\n                              &staging_buffer.memory);\n    NK_ASSERT(result == VK_SUCCESS);\n    result = vkBindBufferMemory(dev->logical_device, staging_buffer.buffer,\n                                staging_buffer.memory, 0);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    result = vkMapMemory(dev->logical_device, staging_buffer.memory, 0,\n                         alloc_info.allocationSize, 0, (void **)&data);\n    NK_ASSERT(result == VK_SUCCESS);\n    memcpy(data, image, width * height * 4);\n    vkUnmapMemory(dev->logical_device, staging_buffer.memory);\n\n    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));\n    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n    NK_ASSERT(dev->command_buffers_len > 0);\n    /*\n    use the same command buffer as for render as we are regenerating the\n    buffer during render anyway\n    */\n    command_buffer = dev->command_buffers[0];\n    result = vkBeginCommandBuffer(command_buffer, &begin_info);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&image_memory_barrier, 0, sizeof(VkImageMemoryBarrier));\n    image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n    image_memory_barrier.image = dev->font_image;\n    image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n    image_memory_barrier.subresourceRange.aspectMask =\n        VK_IMAGE_ASPECT_COLOR_BIT;\n    image_memory_barrier.subresourceRange.levelCount = 1;\n    image_memory_barrier.subresourceRange.layerCount = 1;\n    image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;\n\n    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\n                         VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,\n                         &image_memory_barrier);\n\n    memset(&buffer_copy_region, 0, sizeof(VkBufferImageCopy));\n    buffer_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    buffer_copy_region.imageSubresource.layerCount = 1;\n    buffer_copy_region.imageExtent.width = (uint32_t)width;\n    buffer_copy_region.imageExtent.height = (uint32_t)height;\n    buffer_copy_region.imageExtent.depth = 1;\n\n    vkCmdCopyBufferToImage(\n        command_buffer, staging_buffer.buffer, dev->font_image,\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_copy_region);\n\n    memset(&image_shader_memory_barrier, 0, sizeof(VkImageMemoryBarrier));\n    image_shader_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n    image_shader_memory_barrier.image = dev->font_image;\n    image_shader_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_shader_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_shader_memory_barrier.oldLayout =\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n    image_shader_memory_barrier.newLayout =\n        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n    image_shader_memory_barrier.subresourceRange.aspectMask =\n        VK_IMAGE_ASPECT_COLOR_BIT;\n    image_shader_memory_barrier.subresourceRange.levelCount = 1;\n    image_shader_memory_barrier.subresourceRange.layerCount = 1;\n    image_shader_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,\n    image_shader_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,\n\n    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,\n                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0,\n                         NULL, 1, &image_shader_memory_barrier);\n\n    result = vkEndCommandBuffer(command_buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&fence_create, 0, sizeof(VkFenceCreateInfo));\n    fence_create.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;\n\n    result = vkCreateFence(dev->logical_device, &fence_create, NULL, &fence);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&submit_info, 0, sizeof(VkSubmitInfo));\n    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n    submit_info.commandBufferCount = 1;\n    submit_info.pCommandBuffers = &command_buffer;\n\n    result = vkQueueSubmit(graphics_queue, 1, &submit_info, fence);\n    NK_ASSERT(result == VK_SUCCESS);\n    result =\n        vkWaitForFences(dev->logical_device, 1, &fence, VK_TRUE, UINT64_MAX);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkDestroyFence(dev->logical_device, fence, NULL);\n\n    vkFreeMemory(dev->logical_device, staging_buffer.memory, NULL);\n    vkDestroyBuffer(dev->logical_device, staging_buffer.buffer, NULL);\n\n    memset(&image_view_info, 0, sizeof(VkImageViewCreateInfo));\n    image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n    image_view_info.image = dev->font_image;\n    image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n    image_view_info.format = image_info.format;\n    image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    image_view_info.subresourceRange.layerCount = 1;\n    image_view_info.subresourceRange.levelCount = 1;\n\n    result = vkCreateImageView(dev->logical_device, &image_view_info, NULL,\n                               &dev->font_image_view);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_glfw3_destroy_render_resources(struct nk_glfw_device *dev) {\n    uint32_t i;\n\n    vkDestroyPipeline(dev->logical_device, dev->pipeline, NULL);\n    vkDestroyPipelineLayout(dev->logical_device, dev->pipeline_layout, NULL);\n    vkDestroyDescriptorSetLayout(dev->logical_device,\n                                 dev->texture_descriptor_set_layout, NULL);\n    vkDestroyDescriptorSetLayout(dev->logical_device,\n                                 dev->uniform_descriptor_set_layout, NULL);\n    vkDestroyDescriptorPool(dev->logical_device, dev->descriptor_pool, NULL);\n    for (i = 0; i < dev->framebuffers_len; i++) {\n        vkDestroyFramebuffer(dev->logical_device, dev->framebuffers[i], NULL);\n    }\n    free(dev->framebuffers);\n    dev->framebuffers_len = 0;\n    free(dev->texture_descriptor_sets);\n    dev->texture_descriptor_sets_len = 0;\n    vkDestroyRenderPass(dev->logical_device, dev->render_pass, NULL);\n}\n\nNK_API void nk_glfw3_resize(uint32_t framebuffer_width,\n                            uint32_t framebuffer_height) {\n    struct nk_glfw_device *dev = &glfw.vulkan;\n    glfwGetWindowSize(glfw.win, &glfw.width, &glfw.height);\n    glfwGetFramebufferSize(glfw.win, &glfw.display_width, &glfw.display_height);\n\n    nk_glfw3_destroy_render_resources(dev);\n    nk_glfw3_create_render_resources(dev, framebuffer_width,\n                                     framebuffer_height);\n}\n\nNK_API void nk_glfw3_device_destroy(void) {\n    struct nk_glfw_device *dev = &glfw.vulkan;\n\n    vkDeviceWaitIdle(dev->logical_device);\n\n    nk_glfw3_destroy_render_resources(dev);\n\n    vkFreeCommandBuffers(dev->logical_device, dev->command_pool,\n                         dev->command_buffers_len, dev->command_buffers);\n    vkDestroyCommandPool(dev->logical_device, dev->command_pool, NULL);\n    vkDestroySemaphore(dev->logical_device, dev->render_completed, NULL);\n\n    vkUnmapMemory(dev->logical_device, dev->vertex_memory);\n    vkUnmapMemory(dev->logical_device, dev->index_memory);\n    vkUnmapMemory(dev->logical_device, dev->uniform_memory);\n\n    vkFreeMemory(dev->logical_device, dev->vertex_memory, NULL);\n    vkFreeMemory(dev->logical_device, dev->index_memory, NULL);\n    vkFreeMemory(dev->logical_device, dev->uniform_memory, NULL);\n\n    vkDestroyBuffer(dev->logical_device, dev->vertex_buffer, NULL);\n    vkDestroyBuffer(dev->logical_device, dev->index_buffer, NULL);\n    vkDestroyBuffer(dev->logical_device, dev->uniform_buffer, NULL);\n\n    vkDestroySampler(dev->logical_device, dev->sampler, NULL);\n\n    vkFreeMemory(dev->logical_device, dev->font_memory, NULL);\n    vkDestroyImage(dev->logical_device, dev->font_image, NULL);\n    vkDestroyImageView(dev->logical_device, dev->font_image_view, NULL);\n\n    free(dev->command_buffers);\n    nk_buffer_free(&dev->cmds);\n}\n\nNK_API\nvoid nk_glfw3_shutdown(void) {\n    nk_font_atlas_clear(&glfw.atlas);\n    nk_free(&glfw.ctx);\n    nk_glfw3_device_destroy();\n    memset(&glfw, 0, sizeof(glfw));\n}\n\nNK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas) {\n    nk_font_atlas_init_default(&glfw.atlas);\n    nk_font_atlas_begin(&glfw.atlas);\n    *atlas = &glfw.atlas;\n}\n\nNK_API void nk_glfw3_font_stash_end(VkQueue graphics_queue) {\n    struct nk_glfw_device *dev = &glfw.vulkan;\n\n    const void *image;\n    int w, h;\n    image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_glfw3_device_upload_atlas(graphics_queue, image, w, h);\n    nk_font_atlas_end(&glfw.atlas, nk_handle_ptr(dev->font_image_view),\n                      &dev->tex_null);\n    if (glfw.atlas.default_font) {\n        nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle);\n    }\n}\n\nNK_API void nk_glfw3_new_frame(void) {\n    int i;\n    double x, y;\n    struct nk_context *ctx = &glfw.ctx;\n    struct GLFWwindow *win = glfw.win;\n    nk_char* k_state = glfw.key_events;\n\n    /* update the timer */\n    float delta_time_now = (float)glfwGetTime();\n    glfw.ctx.delta_time_seconds = delta_time_now - glfw.delta_time_seconds_last;\n    glfw.delta_time_seconds_last = delta_time_now;\n\n    glfwGetWindowSize(win, &glfw.width, &glfw.height);\n    glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height);\n    glfw.fb_scale.x = (float)glfw.display_width/(float)glfw.width;\n    glfw.fb_scale.y = (float)glfw.display_height/(float)glfw.height;\n\n    nk_input_begin(ctx);\n    for (i = 0; i < glfw.text_len; ++i)\n        nk_input_unicode(ctx, glfw.text[i]);\n\n#ifdef NK_GLFW_VULKAN_MOUSE_GRABBING\n    /* optional grabbing behavior */\n    if (ctx->input.mouse.grab)\n        glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);\n    else if (ctx->input.mouse.ungrab)\n        glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);\n#endif\n\n    if (k_state[NK_KEY_DEL] >= 0) nk_input_key(ctx, NK_KEY_DEL, k_state[NK_KEY_DEL]);\n    if (k_state[NK_KEY_ENTER] >= 0) nk_input_key(ctx, NK_KEY_ENTER, k_state[NK_KEY_ENTER]);\n\n    if (k_state[NK_KEY_TEXT_RESET_MODE] >= 0) nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, k_state[NK_KEY_TEXT_RESET_MODE]);\n\n    if (k_state[NK_KEY_TAB] >= 0) nk_input_key(ctx, NK_KEY_TAB, k_state[NK_KEY_TAB]);\n    if (k_state[NK_KEY_BACKSPACE] >= 0) nk_input_key(ctx, NK_KEY_BACKSPACE, k_state[NK_KEY_BACKSPACE]);\n    if (k_state[NK_KEY_UP] >= 0) nk_input_key(ctx, NK_KEY_UP, k_state[NK_KEY_UP]);\n    if (k_state[NK_KEY_DOWN] >= 0) nk_input_key(ctx, NK_KEY_DOWN, k_state[NK_KEY_DOWN]);\n    if (k_state[NK_KEY_SCROLL_UP] >= 0) nk_input_key(ctx, NK_KEY_SCROLL_UP, k_state[NK_KEY_SCROLL_UP]);\n    if (k_state[NK_KEY_SCROLL_DOWN] >= 0) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, k_state[NK_KEY_SCROLL_DOWN]);\n\n    if (k_state[NK_KEY_TEXT_INSERT_MODE] >= 0) nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, k_state[NK_KEY_TEXT_INSERT_MODE]);\n    if (k_state[NK_KEY_TEXT_REPLACE_MODE] >= 0) nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, k_state[NK_KEY_TEXT_REPLACE_MODE]);\n\n    nk_input_key(ctx, NK_KEY_TEXT_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_TEXT_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SCROLL_START, glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SCROLL_END, glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SHIFT, glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS||\n                                    glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS);\n\n    if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||\n        glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {\n        /* Note these are physical keys and won't respect any layouts/key mapping */\n        if (k_state[NK_KEY_COPY] >= 0) nk_input_key(ctx, NK_KEY_COPY, k_state[NK_KEY_COPY]);\n        if (k_state[NK_KEY_PASTE] >= 0) nk_input_key(ctx, NK_KEY_PASTE, k_state[NK_KEY_PASTE]);\n        if (k_state[NK_KEY_CUT] >= 0) nk_input_key(ctx, NK_KEY_CUT, k_state[NK_KEY_CUT]);\n        if (k_state[NK_KEY_TEXT_UNDO] >= 0) nk_input_key(ctx, NK_KEY_TEXT_UNDO, k_state[NK_KEY_TEXT_UNDO]);\n        if (k_state[NK_KEY_TEXT_REDO] >= 0) nk_input_key(ctx, NK_KEY_TEXT_REDO, k_state[NK_KEY_TEXT_REDO]);\n        if (k_state[NK_KEY_TEXT_LINE_START] >= 0) nk_input_key(ctx, NK_KEY_TEXT_LINE_START, k_state[NK_KEY_TEXT_LINE_START]);\n        if (k_state[NK_KEY_TEXT_LINE_END] >= 0) nk_input_key(ctx, NK_KEY_TEXT_LINE_END, k_state[NK_KEY_TEXT_LINE_END]);\n        if (k_state[NK_KEY_TEXT_SELECT_ALL] >= 0) nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, k_state[NK_KEY_TEXT_SELECT_ALL]);\n        if (k_state[NK_KEY_LEFT] >= 0) nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, k_state[NK_KEY_LEFT]);\n        if (k_state[NK_KEY_RIGHT] >= 0) nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, k_state[NK_KEY_RIGHT]);\n    } else {\n        if (k_state[NK_KEY_LEFT] >= 0) nk_input_key(ctx, NK_KEY_LEFT, k_state[NK_KEY_LEFT]);\n        if (k_state[NK_KEY_RIGHT] >= 0) nk_input_key(ctx, NK_KEY_RIGHT, k_state[NK_KEY_RIGHT]);\n        nk_input_key(ctx, NK_KEY_COPY, 0);\n        nk_input_key(ctx, NK_KEY_PASTE, 0);\n        nk_input_key(ctx, NK_KEY_CUT, 0);\n    }\n\n    glfwGetCursorPos(win, &x, &y);\n    nk_input_motion(ctx, (int)x, (int)y);\n#ifdef NK_GLFW_VULKAN_MOUSE_GRABBING\n    if (ctx->input.mouse.grabbed) {\n        glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x,\n                         ctx->input.mouse.prev.y);\n        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n    }\n#endif\n    nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y,\n                    glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) ==\n                        GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y,\n                    glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) ==\n                        GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y,\n                    glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) ==\n                        GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_DOUBLE, (int)glfw.double_click_pos.x,\n                    (int)glfw.double_click_pos.y, glfw.is_double_click_down);\n    nk_input_button(ctx, NK_BUTTON_X1, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_4) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_X2, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_5) == GLFW_PRESS);\n    nk_input_scroll(ctx, glfw.scroll);\n    nk_input_end(&glfw.ctx);\n\n    /* clear after nk_input_end (-1 since we're doing up/down boolean) */\n    memset(glfw.key_events, -1, sizeof(glfw.key_events));\n\n    glfw.text_len = 0;\n    glfw.scroll = nk_vec2(0, 0);\n}\n\nNK_INTERN void update_texture_descriptor_set(\n    struct nk_glfw_device *dev,\n    struct nk_vulkan_texture_descriptor_set *texture_descriptor_set,\n    VkImageView image_view) {\n    VkDescriptorImageInfo descriptor_image_info;\n    VkWriteDescriptorSet descriptor_write;\n\n    texture_descriptor_set->image_view = image_view;\n\n    memset(&descriptor_image_info, 0, sizeof(VkDescriptorImageInfo));\n    descriptor_image_info.sampler = dev->sampler;\n    descriptor_image_info.imageView = texture_descriptor_set->image_view;\n    descriptor_image_info.imageLayout =\n        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n\n    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));\n    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n    descriptor_write.dstSet = texture_descriptor_set->descriptor_set;\n    descriptor_write.dstBinding = 0;\n    descriptor_write.dstArrayElement = 0;\n    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    descriptor_write.descriptorCount = 1;\n    descriptor_write.pImageInfo = &descriptor_image_info;\n\n    vkUpdateDescriptorSets(dev->logical_device, 1, &descriptor_write, 0, NULL);\n}\n\nNK_API\nVkSemaphore nk_glfw3_render(VkQueue graphics_queue, uint32_t buffer_index,\n                            VkSemaphore wait_semaphore,\n                            enum nk_anti_aliasing AA) {\n    struct nk_glfw_device *dev = &glfw.vulkan;\n    struct nk_buffer vbuf, ebuf;\n\n    struct Mat4f projection = {\n        {2.0f, 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f,\n         0.0f, -1.0f, 1.0f, 0.0f, 1.0f},\n    };\n\n    VkCommandBufferBeginInfo begin_info;\n    VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 0.0f}}};\n    VkRenderPassBeginInfo render_pass_begin_nfo;\n    VkCommandBuffer command_buffer;\n    VkResult result;\n    VkViewport viewport;\n\n    VkDeviceSize doffset = 0;\n    VkImageView current_texture = NULL;\n    uint32_t index_offset = 0;\n    VkRect2D scissor;\n    uint32_t wait_semaphore_count;\n    VkSemaphore *wait_semaphores;\n    VkPipelineStageFlags wait_stage =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    VkSubmitInfo submit_info;\n\n    projection.m[0] /= glfw.width;\n    projection.m[5] /= glfw.height;\n\n    memcpy(dev->mapped_uniform, &projection, sizeof(projection));\n\n    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));\n    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n    memset(&render_pass_begin_nfo, 0, sizeof(VkRenderPassBeginInfo));\n    render_pass_begin_nfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;\n    render_pass_begin_nfo.renderPass = dev->render_pass;\n    render_pass_begin_nfo.renderArea.extent.width = (uint32_t)glfw.width;\n    render_pass_begin_nfo.renderArea.extent.height = (uint32_t)glfw.height;\n    render_pass_begin_nfo.clearValueCount = 1;\n    render_pass_begin_nfo.pClearValues = &clear_value;\n    render_pass_begin_nfo.framebuffer = dev->framebuffers[buffer_index];\n\n    command_buffer = dev->command_buffers[buffer_index];\n\n    result = vkBeginCommandBuffer(command_buffer, &begin_info);\n    NK_ASSERT(result == VK_SUCCESS);\n    vkCmdBeginRenderPass(command_buffer, &render_pass_begin_nfo,\n                         VK_SUBPASS_CONTENTS_INLINE);\n\n    memset(&viewport, 0, sizeof(VkViewport));\n    viewport.width = (float)glfw.width;\n    viewport.height = (float)glfw.height;\n    viewport.maxDepth = 1.0f;\n    vkCmdSetViewport(command_buffer, 0, 1, &viewport);\n\n    vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                      dev->pipeline);\n    vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                            dev->pipeline_layout, 0, 1,\n                            &dev->uniform_descriptor_set, 0, NULL);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        /* load draw vertices & elements directly into vertex + element buffer\n         */\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] =\n                {{NK_VERTEX_POSITION, NK_FORMAT_FLOAT,\n                  NK_OFFSETOF(struct nk_glfw_vertex, position)},\n                 {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT,\n                  NK_OFFSETOF(struct nk_glfw_vertex, uv)},\n                 {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8,\n                  NK_OFFSETOF(struct nk_glfw_vertex, col)},\n                 {NK_VERTEX_LAYOUT_END}};\n            NK_MEMSET(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_glfw_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            nk_buffer_init_fixed(&vbuf, dev->mapped_vertex,\n                                 (size_t)dev->max_vertex_buffer);\n            nk_buffer_init_fixed(&ebuf, dev->mapped_index,\n                                 (size_t)dev->max_element_buffer);\n            nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n        }\n\n        /* iterate over and execute each draw command */\n\n        vkCmdBindVertexBuffers(command_buffer, 0, 1, &dev->vertex_buffer,\n                               &doffset);\n        vkCmdBindIndexBuffer(command_buffer, dev->index_buffer, 0,\n                             VK_INDEX_TYPE_UINT16);\n\n        nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds) {\n            if (!cmd->texture.ptr) {\n                continue;\n            }\n            if (cmd->texture.ptr && cmd->texture.ptr != current_texture) {\n                int found = 0;\n                uint32_t i;\n                for (i = 0; i < dev->texture_descriptor_sets_len; i++) {\n                    if (dev->texture_descriptor_sets[i].image_view ==\n                        cmd->texture.ptr) {\n                        found = 1;\n                        break;\n                    }\n                }\n\n                if (!found) {\n                    update_texture_descriptor_set(\n                        dev, &dev->texture_descriptor_sets[i],\n                        (VkImageView)cmd->texture.ptr);\n                    dev->texture_descriptor_sets_len++;\n                }\n                vkCmdBindDescriptorSets(\n                    command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                    dev->pipeline_layout, 1, 1,\n                    &dev->texture_descriptor_sets[i].descriptor_set, 0, NULL);\n            }\n\n            if (!cmd->elem_count)\n                continue;\n\n            scissor.offset.x = (int32_t)(NK_MAX(cmd->clip_rect.x, 0.f) * glfw.fb_scale.x);\n            scissor.offset.y = (int32_t)(NK_MAX(cmd->clip_rect.y, 0.f) * glfw.fb_scale.y);\n            scissor.extent.width = (uint32_t)(cmd->clip_rect.w * glfw.fb_scale.x);\n            scissor.extent.height = (uint32_t)(cmd->clip_rect.h * glfw.fb_scale.y);\n            vkCmdSetScissor(command_buffer, 0, 1, &scissor);\n            vkCmdDrawIndexed(command_buffer, cmd->elem_count, 1, index_offset,\n                             0, 0);\n            index_offset += cmd->elem_count;\n        }\n        nk_clear(&glfw.ctx);\n    }\n\n    vkCmdEndRenderPass(command_buffer);\n    result = vkEndCommandBuffer(command_buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    if (wait_semaphore) {\n        wait_semaphore_count = 1;\n        wait_semaphores = &wait_semaphore;\n    } else {\n        wait_semaphore_count = 0;\n        wait_semaphores = NULL;\n    }\n\n    memset(&submit_info, 0, sizeof(VkSubmitInfo));\n    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n    submit_info.commandBufferCount = 1;\n    submit_info.pCommandBuffers = &command_buffer;\n    submit_info.pWaitDstStageMask = &wait_stage;\n    submit_info.waitSemaphoreCount = wait_semaphore_count;\n    submit_info.pWaitSemaphores = wait_semaphores;\n    submit_info.signalSemaphoreCount = 1;\n    submit_info.pSignalSemaphores = &dev->render_completed;\n\n    result = vkQueueSubmit(graphics_queue, 1, &submit_info, NULL);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    return dev->render_completed;\n}\n\nNK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint) {\n    (void)win;\n    if (glfw.text_len < NK_GLFW_TEXT_MAX)\n        glfw.text[glfw.text_len++] = codepoint;\n}\n\nNK_API void\nnk_glfw3_key_callback(GLFWwindow *win, int key, int scancode, int action, int mods)\n{\n    static int insert_toggle = 0;\n    /*\n     * convert GLFW_REPEAT to down (technically GLFW_RELEASE, GLFW_PRESS, GLFW_REPEAT are\n     * already 0, 1, 2 but just to be clearer)\n     */\n    nk_char a = (action == GLFW_RELEASE) ? nk_false : nk_true;\n\n    NK_UNUSED(win);\n    NK_UNUSED(scancode);\n    NK_UNUSED(mods);\n\n    switch (key) {\n    case GLFW_KEY_DELETE:    glfw.key_events[NK_KEY_DEL] = a; break;\n    case GLFW_KEY_TAB:       glfw.key_events[NK_KEY_TAB] = a; break;\n    case GLFW_KEY_BACKSPACE: glfw.key_events[NK_KEY_BACKSPACE] = a; break;\n    case GLFW_KEY_UP:        glfw.key_events[NK_KEY_UP] = a; break;\n    case GLFW_KEY_DOWN:      glfw.key_events[NK_KEY_DOWN] = a; break;\n    case GLFW_KEY_LEFT:      glfw.key_events[NK_KEY_LEFT] = a; break;\n    case GLFW_KEY_RIGHT:     glfw.key_events[NK_KEY_RIGHT] = a; break;\n    case GLFW_KEY_ESCAPE:    glfw.key_events[NK_KEY_TEXT_RESET_MODE] = a; break;\n\n    case GLFW_KEY_PAGE_UP:   glfw.key_events[NK_KEY_SCROLL_UP] = a; break;\n    case GLFW_KEY_PAGE_DOWN: glfw.key_events[NK_KEY_SCROLL_DOWN] = a; break;\n\n    /* have to add all keys used for nuklear to get correct repeat behavior\n     * NOTE these are scancodes so your custom layout won't matter unfortunately\n     * Also while including everything will prevent unnecessary input calls,\n     * only the ones with visible effects really matter, ie paste, undo, redo\n     * selecting all, copying or cutting 40 times before you release the keys\n     * doesn't actually cause any visible problems */\n\n    case GLFW_KEY_C:         glfw.key_events[NK_KEY_COPY] = a; break;\n    case GLFW_KEY_V:         glfw.key_events[NK_KEY_PASTE] = a; break;\n    case GLFW_KEY_X:         glfw.key_events[NK_KEY_CUT] = a; break;\n    case GLFW_KEY_Z:         glfw.key_events[NK_KEY_TEXT_UNDO] = a; break;\n    case GLFW_KEY_R:         glfw.key_events[NK_KEY_TEXT_REDO] = a; break;\n    case GLFW_KEY_B:         glfw.key_events[NK_KEY_TEXT_LINE_START] = a; break;\n    case GLFW_KEY_E:         glfw.key_events[NK_KEY_TEXT_LINE_END] = a; break;\n    case GLFW_KEY_A:         glfw.key_events[NK_KEY_TEXT_SELECT_ALL] = a; break;\n\n    case GLFW_KEY_ENTER:\n    case GLFW_KEY_KP_ENTER:\n        glfw.key_events[NK_KEY_ENTER] = a;\n        break;\n    case GLFW_KEY_INSERT:\n        /* Only switch on release to avoid repeat issues\n         * kind of confusing since we have to negate it but we're already\n         * hacking it since Nuklear treats them as two separate keys rather\n         * than a single toggle state */\n        if (!a) {\n            insert_toggle = !insert_toggle;\n            if (insert_toggle) {\n                glfw.key_events[NK_KEY_TEXT_INSERT_MODE] = !a;\n                /* glfw.key_events[NK_KEY_TEXT_REPLACE_MODE] = a; */\n            } else {\n                /* glfw.key_events[NK_KEY_TEXT_INSERT_MODE] = a; */\n                glfw.key_events[NK_KEY_TEXT_REPLACE_MODE] = !a;\n            }\n        }\n        break;\n    default:\n        ;\n    }\n}\n\nNK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff,\n                                     double yoff) {\n    (void)win;\n    (void)xoff;\n    glfw.scroll.x += (float)xoff;\n    glfw.scroll.y += (float)yoff;\n}\n\nNK_API void nk_glfw3_mouse_button_callback(GLFWwindow *window, int button,\n                                           int action, int mods) {\n    double x, y;\n    NK_UNUSED(mods);\n    if (button != GLFW_MOUSE_BUTTON_LEFT)\n        return;\n    glfwGetCursorPos(window, &x, &y);\n    if (action == GLFW_PRESS) {\n        double dt = glfwGetTime() - glfw.last_button_click;\n        if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) {\n            glfw.is_double_click_down = nk_true;\n            glfw.double_click_pos = nk_vec2((float)x, (float)y);\n        }\n        glfw.last_button_click = glfwGetTime();\n    } else\n        glfw.is_double_click_down = nk_false;\n}\n\nNK_INTERN void nk_glfw3_clipboard_paste(nk_handle usr,\n                                        struct nk_text_edit *edit) {\n    const char *text = glfwGetClipboardString(glfw.win);\n    if (text)\n        nk_textedit_paste(edit, text, nk_strlen(text));\n    (void)usr;\n}\n\nNK_INTERN void nk_glfw3_clipboard_copy(nk_handle usr, const char *text,\n                                       int len) {\n    char *str = 0;\n    (void)usr;\n    if (!len)\n        return;\n    str = (char *)malloc((size_t)len + 1);\n    if (!str)\n        return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n    glfwSetClipboardString(glfw.win, str);\n    free(str);\n}\n\nNK_API struct nk_context *\nnk_glfw3_init(GLFWwindow *win, VkDevice logical_device,\n              VkPhysicalDevice physical_device,\n              uint32_t graphics_queue_family_index, VkImageView *image_views,\n              uint32_t image_views_len, VkFormat color_format,\n              enum nk_glfw_init_state init_state,\n              VkDeviceSize max_vertex_buffer, VkDeviceSize max_element_buffer) {\n    memset(&glfw, 0, sizeof(struct nk_glfw));\n    glfw.win = win;\n    if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {\n        glfwSetScrollCallback(win, nk_gflw3_scroll_callback);\n        glfwSetCharCallback(win, nk_glfw3_char_callback);\n        glfwSetKeyCallback(win, nk_glfw3_key_callback);\n        glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback);\n    }\n    nk_init_default(&glfw.ctx, 0);\n    glfw.ctx.clip.copy = nk_glfw3_clipboard_copy;\n    glfw.ctx.clip.paste = nk_glfw3_clipboard_paste;\n    glfw.ctx.clip.userdata = nk_handle_ptr(0);\n    glfw.last_button_click = 0;\n\n    glfwGetWindowSize(win, &glfw.width, &glfw.height);\n    glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height);\n\n    nk_glfw3_device_create(logical_device, physical_device,\n                           graphics_queue_family_index, image_views,\n                           image_views_len, color_format, max_vertex_buffer,\n                           max_element_buffer, (uint32_t)glfw.display_width,\n                           (uint32_t)glfw.display_height);\n\n    glfw.is_double_click_down = nk_false;\n    glfw.double_click_pos = nk_vec2(0, 0);\n\n    return &glfw.ctx;\n}\n\n#endif\n"
  },
  {
    "path": "demo/glfw_vulkan/shaders/demo.frag",
    "content": "#version 450\n#extension GL_ARB_separate_shader_objects : enable\n\nlayout(binding = 0) uniform sampler2D overlay;\n\nlayout(location = 0) in vec2 inUV;\n\nlayout(location = 0) out vec4 outColor;\n\nvoid main() {\n    outColor = texture(overlay, inUV);\n}\n"
  },
  {
    "path": "demo/glfw_vulkan/shaders/demo.vert",
    "content": "#version 450\n#extension GL_ARB_separate_shader_objects : enable\n\nlayout (location = 0) out vec2 outUV;\n\nvoid main()\n{\n    outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);\n    gl_Position = vec4(outUV * 2.0f + -1.0f, 0.0f, 1.0f);\n}\n"
  },
  {
    "path": "demo/glfw_vulkan/src/Makefile",
    "content": "create_shader_inlined_header: nuklearshaders/nuklear.vert.spv nuklearshaders/nuklear.frag.spv\n\tawk -v st='// NUKLEAR_SHADERS_START' -v et='// NUKLEAR_SHADERS_END' -v repl=\"$$(xxd -i nuklearshaders/nuklear.vert.spv && xxd -i nuklearshaders/nuklear.frag.spv)\" '$$0 == st{del=1} $$0 == et{$$0 = repl; del=0} !del' nuklear_glfw_vulkan.in.h > nuklear_glfw_vulkan.h\n\nnuklearshaders/nuklear.vert.spv: nuklearshaders/nuklear.vert\n\tglslc --target-env=vulkan nuklearshaders/nuklear.vert -o nuklearshaders/nuklear.vert.spv\n\nnuklearshaders/nuklear.frag.spv: nuklearshaders/nuklear.frag\n\tglslc --target-env=vulkan nuklearshaders/nuklear.frag -o nuklearshaders/nuklear.frag.spv\n\nclean:\n\trm nuklearshaders/nuklear.vert.spv nuklearshaders/nuklear.frag.spv nuklear_glfw_vulkan.h\n"
  },
  {
    "path": "demo/glfw_vulkan/src/README.md",
    "content": "Contrary to OpenGL Vulkan needs precompiled shaders in the SPIR-V format which makes it a bit more difficult to inline the shadercode.\n\nAfter executing `make` the result should be a self contained `nuklear_glfw_vulkan.h`. Copy the result file to the parent directory and the \"release\" should be done.\n\nYou will need to have `xxd`, `glslc` and `awk` installed for this.\n"
  },
  {
    "path": "demo/glfw_vulkan/src/nuklear_glfw_vulkan.in.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_GLFW_VULKAN_H_\n#define NK_GLFW_VULKAN_H_\n\n// NUKLEAR_SHADERS_START\n// will be replaced with the real shader code\n// so we can have some ide support while editing the .in file\n#include \"nuklear.h\"\n\nunsigned char nuklearshaders_nuklear_vert_spv[] = {};\nunsigned int nuklearshaders_nuklear_vert_spv_len = 0;\nunsigned char nuklearshaders_nuklear_frag_spv[] = {};\nunsigned int nuklearshaders_nuklear_frag_spv_len = 0;\n// NUKLEAR_SHADERS_END\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n#define GLFW_INCLUDE_VULKAN\n#include <GLFW/glfw3.h>\n\nenum nk_glfw_init_state { NK_GLFW3_DEFAULT = 0, NK_GLFW3_INSTALL_CALLBACKS };\n\nNK_API struct nk_context *\nnk_glfw3_init(GLFWwindow *win, VkDevice logical_device,\n              VkPhysicalDevice physical_device,\n              uint32_t graphics_queue_family_index, VkImageView *image_views,\n              uint32_t image_views_len, VkFormat color_format,\n              enum nk_glfw_init_state init_state,\n              VkDeviceSize max_vertex_buffer, VkDeviceSize max_element_buffer);\nNK_API void nk_glfw3_shutdown(void);\nNK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void nk_glfw3_font_stash_end(VkQueue graphics_queue);\nNK_API void nk_glfw3_new_frame();\nNK_API VkSemaphore nk_glfw3_render(VkQueue graphics_queue,\n                                   uint32_t buffer_index,\n                                   VkSemaphore wait_semaphore,\n                                   enum nk_anti_aliasing AA);\nNK_API void nk_glfw3_resize(uint32_t framebuffer_width,\n                            uint32_t framebuffer_height);\nNK_API void nk_glfw3_device_destroy(void);\nNK_API void nk_glfw3_device_create(\n    VkDevice logical_device, VkPhysicalDevice physical_device,\n    uint32_t graphics_queue_family_index, VkImageView *image_views,\n    uint32_t image_views_len, VkFormat color_format,\n    VkDeviceSize max_vertex_buffer, VkDeviceSize max_element_buffer,\n    uint32_t framebuffer_width, uint32_t framebuffer_height);\n\nNK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint);\nNK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff, double yoff);\nNK_API void nk_glfw3_mouse_button_callback(GLFWwindow *win, int button,\n                                           int action, int mods);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_GLFW_VULKAN_IMPLEMENTATION\n#undef NK_GLFW_VULKAN_IMPLEMENTATION\n#include <stdlib.h>\n\n#ifndef NK_GLFW_TEXT_MAX\n#define NK_GLFW_TEXT_MAX 256\n#endif\n#ifndef NK_GLFW_DOUBLE_CLICK_LO\n#define NK_GLFW_DOUBLE_CLICK_LO 0.02\n#endif\n#ifndef NK_GLFW_DOUBLE_CLICK_HI\n#define NK_GLFW_DOUBLE_CLICK_HI 0.2\n#endif\n#ifndef NK_GLFW_MAX_TEXTURES\n#define NK_GLFW_MAX_TEXTURES 256\n#endif\n\n#define VK_COLOR_COMPONENT_MASK_RGBA                                           \\\n    VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |                      \\\n        VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT\n\nstruct nk_glfw_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstruct nk_vulkan_texture_descriptor_set {\n    VkImageView image_view;\n    VkDescriptorSet descriptor_set;\n};\n\nstruct nk_glfw_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    int max_vertex_buffer;\n    int max_element_buffer;\n    VkDevice logical_device;\n    VkPhysicalDevice physical_device;\n    VkImageView *image_views;\n    uint32_t image_views_len;\n    VkFormat color_format;\n    VkFramebuffer *framebuffers;\n    uint32_t framebuffers_len;\n    VkCommandBuffer *command_buffers;\n    uint32_t command_buffers_len;\n    VkSampler sampler;\n    VkCommandPool command_pool;\n    VkSemaphore render_completed;\n    VkBuffer vertex_buffer;\n    VkDeviceMemory vertex_memory;\n    void *mapped_vertex;\n    VkBuffer index_buffer;\n    VkDeviceMemory index_memory;\n    void *mapped_index;\n    VkBuffer uniform_buffer;\n    VkDeviceMemory uniform_memory;\n    void *mapped_uniform;\n    VkRenderPass render_pass;\n    VkDescriptorPool descriptor_pool;\n    VkDescriptorSetLayout uniform_descriptor_set_layout;\n    VkDescriptorSet uniform_descriptor_set;\n    VkDescriptorSetLayout texture_descriptor_set_layout;\n    struct nk_vulkan_texture_descriptor_set *texture_descriptor_sets;\n    uint32_t texture_descriptor_sets_len;\n    VkPipelineLayout pipeline_layout;\n    VkPipeline pipeline;\n    VkImage font_image;\n    VkImageView font_image_view;\n    VkDeviceMemory font_memory;\n};\n\nstatic struct nk_glfw {\n    GLFWwindow *win;\n    int width, height;\n    int display_width, display_height;\n    struct nk_glfw_device vulkan;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    unsigned int text[NK_GLFW_TEXT_MAX];\n    int text_len;\n    struct nk_vec2 scroll;\n    double last_button_click;\n    int is_double_click_down;\n    struct nk_vec2 double_click_pos;\n    float delta_time_seconds_last;\n} glfw;\n\nstruct Mat4f {\n    float m[16];\n};\n\nNK_INTERN uint32_t nk_glfw3_find_memory_index(\n    VkPhysicalDevice physical_device, uint32_t type_filter,\n    VkMemoryPropertyFlags properties) {\n    VkPhysicalDeviceMemoryProperties mem_properties;\n    uint32_t i;\n\n    vkGetPhysicalDeviceMemoryProperties(physical_device, &mem_properties);\n    for (i = 0; i < mem_properties.memoryTypeCount; i++) {\n        if ((type_filter & (1 << i)) &&\n            (mem_properties.memoryTypes[i].propertyFlags & properties) ==\n                properties) {\n            return i;\n        }\n    }\n\n    assert(0);\n    return 0;\n}\n\nNK_INTERN void nk_glfw3_create_sampler(struct nk_glfw_device *dev) {\n    VkResult result;\n    VkSamplerCreateInfo sampler_info;\n    memset(&sampler_info, 0, sizeof(VkSamplerCreateInfo));\n\n    sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n    sampler_info.pNext = NULL;\n    sampler_info.maxAnisotropy = 1.0;\n    sampler_info.magFilter = VK_FILTER_LINEAR;\n    sampler_info.minFilter = VK_FILTER_LINEAR;\n    sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n    sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.mipLodBias = 0.0f;\n    sampler_info.compareEnable = VK_FALSE;\n    sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;\n    sampler_info.minLod = 0.0f;\n    sampler_info.maxLod = 0.0f;\n    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;\n\n    result = vkCreateSampler(dev->logical_device, &sampler_info, NULL,\n                             &dev->sampler);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_glfw3_create_command_pool(struct nk_glfw_device *dev,\n                             uint32_t graphics_queue_family_index) {\n    VkResult result;\n    VkCommandPoolCreateInfo pool_info;\n    memset(&pool_info, 0, sizeof(VkCommandPoolCreateInfo));\n\n    pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;\n    pool_info.queueFamilyIndex = graphics_queue_family_index;\n    pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;\n    result = vkCreateCommandPool(dev->logical_device, &pool_info, NULL,\n                                 &dev->command_pool);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_glfw3_create_command_buffers(struct nk_glfw_device *dev) {\n    VkResult result;\n    VkCommandBufferAllocateInfo allocate_info;\n    memset(&allocate_info, 0, sizeof(VkCommandBufferAllocateInfo));\n\n    dev->command_buffers = (VkCommandBuffer *)malloc(dev->image_views_len *\n                                                     sizeof(VkCommandBuffer));\n    dev->command_buffers_len = dev->image_views_len;\n\n    allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;\n    allocate_info.commandPool = dev->command_pool;\n    allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;\n    allocate_info.commandBufferCount = dev->command_buffers_len;\n\n    result = vkAllocateCommandBuffers(dev->logical_device, &allocate_info,\n                                      dev->command_buffers);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_glfw3_create_semaphore(struct nk_glfw_device *dev) {\n    VkResult result;\n    VkSemaphoreCreateInfo semaphore_info;\n    memset(&semaphore_info, 0, sizeof(VkSemaphoreCreateInfo));\n\n    semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;\n    result = (vkCreateSemaphore(dev->logical_device, &semaphore_info, NULL,\n                                &dev->render_completed));\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_glfw3_create_buffer_and_memory(struct nk_glfw_device *dev,\n                                                 VkBuffer *buffer,\n                                                 VkBufferUsageFlags usage,\n                                                 VkDeviceMemory *memory,\n                                                 VkDeviceSize size) {\n    VkMemoryRequirements mem_reqs;\n    VkResult result;\n    VkBufferCreateInfo buffer_info;\n    VkMemoryAllocateInfo alloc_info;\n\n    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));\n    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n    buffer_info.size = size;\n    buffer_info.usage = usage;\n    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    result = vkCreateBuffer(dev->logical_device, &buffer_info, NULL, buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkGetBufferMemoryRequirements(dev->logical_device, *buffer, &mem_reqs);\n\n    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n    alloc_info.allocationSize = mem_reqs.size;\n    alloc_info.memoryTypeIndex = nk_glfw3_find_memory_index(\n        dev->physical_device, mem_reqs.memoryTypeBits,\n        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n            VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\n    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL, memory);\n    NK_ASSERT(result == VK_SUCCESS);\n    result = vkBindBufferMemory(dev->logical_device, *buffer, *memory, 0);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_glfw3_create_render_pass(struct nk_glfw_device *dev) {\n    VkAttachmentDescription attachment;\n    VkAttachmentReference color_reference;\n    VkSubpassDependency subpass_dependency;\n    VkSubpassDescription subpass_description;\n    VkRenderPassCreateInfo render_pass_info;\n    VkResult result;\n\n    memset(&attachment, 0, sizeof(VkAttachmentDescription));\n    attachment.format = dev->color_format;\n    attachment.samples = VK_SAMPLE_COUNT_1_BIT;\n    attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;\n    attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n    attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n    attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n    attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    attachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n\n    memset(&color_reference, 0, sizeof(VkAttachmentReference));\n    color_reference.attachment = 0;\n    color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;\n\n    memset(&subpass_dependency, 0, sizeof(VkSubpassDependency));\n    subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;\n    subpass_dependency.srcAccessMask = 0;\n    subpass_dependency.srcStageMask =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    subpass_dependency.dstSubpass = 0;\n    subpass_dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |\n                                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n    subpass_dependency.dstStageMask =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n\n    memset(&subpass_description, 0, sizeof(VkSubpassDescription));\n    subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;\n    subpass_description.colorAttachmentCount = 1;\n    subpass_description.pColorAttachments = &color_reference;\n\n    memset(&render_pass_info, 0, sizeof(VkRenderPassCreateInfo));\n    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;\n    render_pass_info.attachmentCount = 1;\n    render_pass_info.pAttachments = &attachment;\n    render_pass_info.subpassCount = 1;\n    render_pass_info.pSubpasses = &subpass_description;\n    render_pass_info.dependencyCount = 1;\n    render_pass_info.pDependencies = &subpass_dependency;\n\n    result = vkCreateRenderPass(dev->logical_device, &render_pass_info, NULL,\n                                &dev->render_pass);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_glfw3_create_framebuffers(struct nk_glfw_device *dev,\n                                            uint32_t framebuffer_width,\n                                            uint32_t framebuffer_height) {\n\n    VkFramebufferCreateInfo framebuffer_create_info;\n    uint32_t i;\n    VkResult result;\n\n    dev->framebuffers =\n        (VkFramebuffer *)malloc(dev->image_views_len * sizeof(VkFramebuffer));\n\n    memset(&framebuffer_create_info, 0, sizeof(VkFramebufferCreateInfo));\n    framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;\n    framebuffer_create_info.renderPass = dev->render_pass;\n    framebuffer_create_info.attachmentCount = 1;\n    framebuffer_create_info.width = framebuffer_width;\n    framebuffer_create_info.height = framebuffer_height;\n    framebuffer_create_info.layers = 1;\n    for (i = 0; i < dev->image_views_len; i++) {\n        framebuffer_create_info.pAttachments = &dev->image_views[i];\n        result =\n            vkCreateFramebuffer(dev->logical_device, &framebuffer_create_info,\n                                NULL, &dev->framebuffers[i]);\n        NK_ASSERT(result == VK_SUCCESS);\n    }\n    dev->framebuffers_len = dev->image_views_len;\n}\n\nNK_INTERN void nk_glfw3_create_descriptor_pool(struct nk_glfw_device *dev) {\n    VkDescriptorPoolSize pool_sizes[2];\n    VkDescriptorPoolCreateInfo pool_info;\n    VkResult result;\n\n    memset(&pool_sizes, 0, sizeof(VkDescriptorPoolSize) * 2);\n    pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n    pool_sizes[0].descriptorCount = 1;\n    pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    pool_sizes[1].descriptorCount = NK_GLFW_MAX_TEXTURES;\n\n    memset(&pool_info, 0, sizeof(VkDescriptorPoolCreateInfo));\n    pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;\n    pool_info.poolSizeCount = 2;\n    pool_info.pPoolSizes = pool_sizes;\n    pool_info.maxSets = 1 + NK_GLFW_MAX_TEXTURES;\n\n    result = vkCreateDescriptorPool(dev->logical_device, &pool_info, NULL,\n                                    &dev->descriptor_pool);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_glfw3_create_uniform_descriptor_set_layout(struct nk_glfw_device *dev) {\n    VkDescriptorSetLayoutBinding binding;\n    VkDescriptorSetLayoutCreateInfo descriptor_set_info;\n    VkResult result;\n\n    memset(&binding, 0, sizeof(VkDescriptorSetLayoutBinding));\n    binding.binding = 0;\n    binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n    binding.descriptorCount = 1;\n    binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;\n\n    memset(&descriptor_set_info, 0, sizeof(VkDescriptorSetLayoutCreateInfo));\n    descriptor_set_info.sType =\n        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n    descriptor_set_info.bindingCount = 1;\n    descriptor_set_info.pBindings = &binding;\n\n    result =\n        vkCreateDescriptorSetLayout(dev->logical_device, &descriptor_set_info,\n                                    NULL, &dev->uniform_descriptor_set_layout);\n\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_glfw3_create_and_update_uniform_descriptor_set(struct nk_glfw_device *dev) {\n    VkDescriptorSetAllocateInfo allocate_info;\n    VkDescriptorBufferInfo buffer_info;\n    VkWriteDescriptorSet descriptor_write;\n    VkResult result;\n\n    memset(&allocate_info, 0, sizeof(VkDescriptorSetAllocateInfo));\n    allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n    allocate_info.descriptorPool = dev->descriptor_pool;\n    allocate_info.descriptorSetCount = 1;\n    allocate_info.pSetLayouts = &dev->uniform_descriptor_set_layout;\n\n    result = vkAllocateDescriptorSets(dev->logical_device, &allocate_info,\n                                      &dev->uniform_descriptor_set);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&buffer_info, 0, sizeof(VkDescriptorBufferInfo));\n    buffer_info.buffer = dev->uniform_buffer;\n    buffer_info.offset = 0;\n    buffer_info.range = sizeof(struct Mat4f);\n\n    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));\n    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n    descriptor_write.dstSet = dev->uniform_descriptor_set;\n    descriptor_write.dstBinding = 0;\n    descriptor_write.dstArrayElement = 0;\n    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n    descriptor_write.descriptorCount = 1;\n    descriptor_write.pBufferInfo = &buffer_info;\n\n    vkUpdateDescriptorSets(dev->logical_device, 1, &descriptor_write, 0, NULL);\n}\n\nNK_INTERN void\nnk_glfw3_create_texture_descriptor_set_layout(struct nk_glfw_device *dev) {\n    VkDescriptorSetLayoutBinding binding;\n    VkDescriptorSetLayoutCreateInfo descriptor_set_info;\n    VkResult result;\n\n    memset(&binding, 0, sizeof(VkDescriptorSetLayoutBinding));\n    binding.binding = 0;\n    binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    binding.descriptorCount = 1;\n    binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;\n\n    memset(&descriptor_set_info, 0, sizeof(VkDescriptorSetLayoutCreateInfo));\n    descriptor_set_info.sType =\n        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n    descriptor_set_info.bindingCount = 1;\n    descriptor_set_info.pBindings = &binding;\n\n    result =\n        vkCreateDescriptorSetLayout(dev->logical_device, &descriptor_set_info,\n                                    NULL, &dev->texture_descriptor_set_layout);\n\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_glfw3_create_texture_descriptor_sets(struct nk_glfw_device *dev) {\n    VkDescriptorSetLayout *descriptor_set_layouts;\n    VkDescriptorSet *descriptor_sets;\n    VkDescriptorSetAllocateInfo allocate_info;\n    VkResult result;\n    int i;\n\n    descriptor_set_layouts = (VkDescriptorSetLayout *)malloc(\n        NK_GLFW_MAX_TEXTURES * sizeof(VkDescriptorSetLayout));\n    descriptor_sets = (VkDescriptorSet *)malloc(NK_GLFW_MAX_TEXTURES *\n                                                sizeof(VkDescriptorSet));\n\n    dev->texture_descriptor_sets =\n        (struct nk_vulkan_texture_descriptor_set *)malloc(\n            NK_GLFW_MAX_TEXTURES *\n            sizeof(struct nk_vulkan_texture_descriptor_set));\n    dev->texture_descriptor_sets_len = 0;\n\n    for (i = 0; i < NK_GLFW_MAX_TEXTURES; i++) {\n        descriptor_set_layouts[i] = dev->texture_descriptor_set_layout;\n        descriptor_sets[i] = dev->texture_descriptor_sets[i].descriptor_set;\n    }\n\n    memset(&allocate_info, 0, sizeof(VkDescriptorSetAllocateInfo));\n    allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n    allocate_info.descriptorPool = dev->descriptor_pool;\n    allocate_info.descriptorSetCount = NK_GLFW_MAX_TEXTURES;\n    allocate_info.pSetLayouts = descriptor_set_layouts;\n\n    result = vkAllocateDescriptorSets(dev->logical_device, &allocate_info,\n                                      descriptor_sets);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    for (i = 0; i < NK_GLFW_MAX_TEXTURES; i++) {\n        dev->texture_descriptor_sets[i].descriptor_set = descriptor_sets[i];\n    }\n    free(descriptor_set_layouts);\n    free(descriptor_sets);\n}\n\nNK_INTERN void nk_glfw3_create_pipeline_layout(struct nk_glfw_device *dev) {\n    VkPipelineLayoutCreateInfo pipeline_layout_info;\n    VkDescriptorSetLayout descriptor_set_layouts[2];\n    VkResult result;\n\n    descriptor_set_layouts[0] = dev->uniform_descriptor_set_layout;\n    descriptor_set_layouts[1] = dev->texture_descriptor_set_layout;\n\n    memset(&pipeline_layout_info, 0, sizeof(VkPipelineLayoutCreateInfo));\n    pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;\n    pipeline_layout_info.setLayoutCount = 2;\n    pipeline_layout_info.pSetLayouts = descriptor_set_layouts;\n\n    result = (vkCreatePipelineLayout(dev->logical_device, &pipeline_layout_info,\n                                     NULL, &dev->pipeline_layout));\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN VkPipelineShaderStageCreateInfo\nnk_glfw3_create_shader(struct nk_glfw_device *dev, unsigned char *spv_shader,\n                       uint32_t size, VkShaderStageFlagBits stage_bit) {\n    VkShaderModuleCreateInfo create_info;\n    VkPipelineShaderStageCreateInfo shader_info;\n    VkShaderModule module = NULL;\n    VkResult result;\n\n    memset(&create_info, 0, sizeof(VkShaderModuleCreateInfo));\n    create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;\n    create_info.codeSize = size;\n    create_info.pCode = (const uint32_t *)spv_shader;\n    result =\n        vkCreateShaderModule(dev->logical_device, &create_info, NULL, &module);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&shader_info, 0, sizeof(VkPipelineShaderStageCreateInfo));\n    shader_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;\n    shader_info.stage = stage_bit;\n    shader_info.module = module;\n    shader_info.pName = \"main\";\n    return shader_info;\n}\n\nNK_INTERN void nk_glfw3_create_pipeline(struct nk_glfw_device *dev) {\n    VkPipelineInputAssemblyStateCreateInfo input_assembly_state;\n    VkPipelineRasterizationStateCreateInfo rasterization_state;\n    VkPipelineColorBlendAttachmentState attachment_state = {\n        VK_TRUE,\n        VK_BLEND_FACTOR_SRC_ALPHA,\n        VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,\n        VK_BLEND_OP_ADD,\n        VK_BLEND_FACTOR_SRC_ALPHA,\n        VK_BLEND_FACTOR_ONE,\n        VK_BLEND_OP_ADD,\n        VK_COLOR_COMPONENT_MASK_RGBA,\n    };\n    VkPipelineColorBlendStateCreateInfo color_blend_state;\n    VkPipelineViewportStateCreateInfo viewport_state;\n    VkPipelineMultisampleStateCreateInfo multisample_state;\n    VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT,\n                                        VK_DYNAMIC_STATE_SCISSOR};\n    VkPipelineDynamicStateCreateInfo dynamic_state;\n    VkPipelineShaderStageCreateInfo shader_stages[2];\n    VkVertexInputBindingDescription vertex_input_info;\n    VkVertexInputAttributeDescription vertex_attribute_description[3];\n    VkPipelineVertexInputStateCreateInfo vertex_input;\n    VkGraphicsPipelineCreateInfo pipeline_info;\n    VkResult result;\n\n    memset(&input_assembly_state, 0,\n           sizeof(VkPipelineInputAssemblyStateCreateInfo));\n    input_assembly_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;\n    input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;\n    input_assembly_state.primitiveRestartEnable = VK_FALSE;\n\n    memset(&rasterization_state, 0,\n           sizeof(VkPipelineRasterizationStateCreateInfo));\n    rasterization_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;\n    rasterization_state.polygonMode = VK_POLYGON_MODE_FILL;\n    rasterization_state.cullMode = VK_CULL_MODE_NONE;\n    rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;\n    rasterization_state.lineWidth = 1.0f;\n\n    memset(&color_blend_state, 0, sizeof(VkPipelineColorBlendStateCreateInfo));\n    color_blend_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;\n    color_blend_state.attachmentCount = 1;\n    color_blend_state.pAttachments = &attachment_state;\n\n    memset(&viewport_state, 0, sizeof(VkPipelineViewportStateCreateInfo));\n    viewport_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;\n    viewport_state.viewportCount = 1;\n    viewport_state.scissorCount = 1;\n\n    memset(&multisample_state, 0, sizeof(VkPipelineMultisampleStateCreateInfo));\n    multisample_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;\n    multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;\n\n    memset(&dynamic_state, 0, sizeof(VkPipelineDynamicStateCreateInfo));\n    dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;\n    dynamic_state.pDynamicStates = dynamic_states;\n    dynamic_state.dynamicStateCount = 2;\n\n    shader_stages[0] = nk_glfw3_create_shader(\n        dev, nuklearshaders_nuklear_vert_spv,\n        nuklearshaders_nuklear_vert_spv_len, VK_SHADER_STAGE_VERTEX_BIT);\n    shader_stages[1] = nk_glfw3_create_shader(\n        dev, nuklearshaders_nuklear_frag_spv,\n        nuklearshaders_nuklear_frag_spv_len, VK_SHADER_STAGE_FRAGMENT_BIT);\n\n    memset(&vertex_input_info, 0, sizeof(VkVertexInputBindingDescription));\n    vertex_input_info.binding = 0;\n    vertex_input_info.stride = sizeof(struct nk_glfw_vertex);\n    vertex_input_info.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;\n\n    memset(&vertex_attribute_description, 0,\n           sizeof(VkVertexInputAttributeDescription) * 3);\n    vertex_attribute_description[0].location = 0;\n    vertex_attribute_description[0].format = VK_FORMAT_R32G32_SFLOAT;\n    vertex_attribute_description[0].offset =\n        NK_OFFSETOF(struct nk_glfw_vertex, position);\n    vertex_attribute_description[1].location = 1;\n    vertex_attribute_description[1].format = VK_FORMAT_R32G32_SFLOAT;\n    vertex_attribute_description[1].offset =\n        NK_OFFSETOF(struct nk_glfw_vertex, uv);\n    vertex_attribute_description[2].location = 2;\n    vertex_attribute_description[2].format = VK_FORMAT_R8G8B8A8_UINT;\n    vertex_attribute_description[2].offset =\n        NK_OFFSETOF(struct nk_glfw_vertex, col);\n\n    memset(&vertex_input, 0, sizeof(VkPipelineVertexInputStateCreateInfo));\n    vertex_input.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;\n    vertex_input.vertexBindingDescriptionCount = 1;\n    vertex_input.pVertexBindingDescriptions = &vertex_input_info;\n    vertex_input.vertexAttributeDescriptionCount = 3;\n    vertex_input.pVertexAttributeDescriptions = vertex_attribute_description;\n\n    memset(&pipeline_info, 0, sizeof(VkGraphicsPipelineCreateInfo));\n    pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;\n    pipeline_info.flags = 0;\n    pipeline_info.stageCount = 2;\n    pipeline_info.pStages = shader_stages;\n    pipeline_info.pVertexInputState = &vertex_input;\n    pipeline_info.pInputAssemblyState = &input_assembly_state;\n    pipeline_info.pViewportState = &viewport_state;\n    pipeline_info.pRasterizationState = &rasterization_state;\n    pipeline_info.pMultisampleState = &multisample_state;\n    pipeline_info.pColorBlendState = &color_blend_state;\n    pipeline_info.pDynamicState = &dynamic_state;\n    pipeline_info.layout = dev->pipeline_layout;\n    pipeline_info.renderPass = dev->render_pass;\n    pipeline_info.basePipelineIndex = -1;\n    pipeline_info.basePipelineHandle = NULL;\n\n    result = vkCreateGraphicsPipelines(dev->logical_device, NULL, 1,\n                                       &pipeline_info, NULL, &dev->pipeline);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkDestroyShaderModule(dev->logical_device, shader_stages[0].module, NULL);\n    vkDestroyShaderModule(dev->logical_device, shader_stages[1].module, NULL);\n}\n\nNK_INTERN void nk_glfw3_create_render_resources(struct nk_glfw_device *dev,\n                                                uint32_t framebuffer_width,\n                                                uint32_t framebuffer_height) {\n    nk_glfw3_create_render_pass(dev);\n    nk_glfw3_create_framebuffers(dev, framebuffer_width, framebuffer_height);\n    nk_glfw3_create_descriptor_pool(dev);\n    nk_glfw3_create_uniform_descriptor_set_layout(dev);\n    nk_glfw3_create_and_update_uniform_descriptor_set(dev);\n    nk_glfw3_create_texture_descriptor_set_layout(dev);\n    nk_glfw3_create_texture_descriptor_sets(dev);\n    nk_glfw3_create_pipeline_layout(dev);\n    nk_glfw3_create_pipeline(dev);\n}\n\nNK_API void nk_glfw3_device_create(\n    VkDevice logical_device, VkPhysicalDevice physical_device,\n    uint32_t graphics_queue_family_index, VkImageView *image_views,\n    uint32_t image_views_len, VkFormat color_format,\n    VkDeviceSize max_vertex_buffer, VkDeviceSize max_element_buffer,\n    uint32_t framebuffer_width, uint32_t framebuffer_height) {\n    struct nk_glfw_device *dev = &glfw.vulkan;\n    dev->max_vertex_buffer = max_vertex_buffer;\n    dev->max_element_buffer = max_element_buffer;\n    nk_buffer_init_default(&dev->cmds);\n    dev->logical_device = logical_device;\n    dev->physical_device = physical_device;\n    dev->image_views = image_views;\n    dev->image_views_len = image_views_len;\n    dev->color_format = color_format;\n    dev->framebuffers = NULL;\n    dev->framebuffers_len = 0;\n\n    nk_glfw3_create_sampler(dev);\n    nk_glfw3_create_command_pool(dev, graphics_queue_family_index);\n    nk_glfw3_create_command_buffers(dev);\n    nk_glfw3_create_semaphore(dev);\n\n    nk_glfw3_create_buffer_and_memory(dev, &dev->vertex_buffer,\n                                      VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,\n                                      &dev->vertex_memory, max_vertex_buffer);\n    nk_glfw3_create_buffer_and_memory(dev, &dev->index_buffer,\n                                      VK_BUFFER_USAGE_INDEX_BUFFER_BIT,\n                                      &dev->index_memory, max_element_buffer);\n    nk_glfw3_create_buffer_and_memory(\n        dev, &dev->uniform_buffer, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,\n        &dev->uniform_memory, sizeof(struct Mat4f));\n\n    vkMapMemory(dev->logical_device, dev->vertex_memory, 0, max_vertex_buffer,\n                0, &dev->mapped_vertex);\n    vkMapMemory(dev->logical_device, dev->index_memory, 0, max_element_buffer,\n                0, &dev->mapped_index);\n    vkMapMemory(dev->logical_device, dev->uniform_memory, 0,\n                sizeof(struct Mat4f), 0, &dev->mapped_uniform);\n\n    nk_glfw3_create_render_resources(dev, framebuffer_width,\n                                     framebuffer_height);\n}\n\nNK_INTERN void nk_glfw3_device_upload_atlas(VkQueue graphics_queue,\n                                            const void *image, int width,\n                                            int height) {\n    struct nk_glfw_device *dev = &glfw.vulkan;\n\n    VkImageCreateInfo image_info;\n    VkResult result;\n    VkMemoryRequirements mem_reqs;\n    VkMemoryAllocateInfo alloc_info;\n    VkBufferCreateInfo buffer_info;\n    uint8_t *data = 0;\n    VkCommandBufferBeginInfo begin_info;\n    VkCommandBuffer command_buffer;\n    VkImageMemoryBarrier image_memory_barrier;\n    VkBufferImageCopy buffer_copy_region;\n    VkImageMemoryBarrier image_shader_memory_barrier;\n    VkFence fence;\n    VkFenceCreateInfo fence_create;\n    VkSubmitInfo submit_info;\n    VkImageViewCreateInfo image_view_info;\n    struct {\n        VkDeviceMemory memory;\n        VkBuffer buffer;\n    } staging_buffer;\n\n    memset(&image_info, 0, sizeof(VkImageCreateInfo));\n    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n    image_info.imageType = VK_IMAGE_TYPE_2D;\n    image_info.format = VK_FORMAT_R8G8B8A8_UNORM;\n    image_info.extent.width = (uint32_t)width;\n    image_info.extent.height = (uint32_t)height;\n    image_info.extent.depth = 1;\n    image_info.mipLevels = 1;\n    image_info.arrayLayers = 1;\n    image_info.samples = VK_SAMPLE_COUNT_1_BIT;\n    image_info.tiling = VK_IMAGE_TILING_OPTIMAL;\n    image_info.usage =\n        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;\n    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\n    result =\n        vkCreateImage(dev->logical_device, &image_info, NULL, &dev->font_image);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkGetImageMemoryRequirements(dev->logical_device, dev->font_image,\n                                 &mem_reqs);\n\n    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n    alloc_info.allocationSize = mem_reqs.size;\n    alloc_info.memoryTypeIndex = nk_glfw3_find_memory_index(\n        dev->physical_device, mem_reqs.memoryTypeBits,\n        VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);\n\n    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL,\n                              &dev->font_memory);\n    NK_ASSERT(result == VK_SUCCESS);\n    result = vkBindImageMemory(dev->logical_device, dev->font_image,\n                               dev->font_memory, 0);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));\n    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n    buffer_info.size = alloc_info.allocationSize;\n    buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;\n    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    result = vkCreateBuffer(dev->logical_device, &buffer_info, NULL,\n                            &staging_buffer.buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n    vkGetBufferMemoryRequirements(dev->logical_device, staging_buffer.buffer,\n                                  &mem_reqs);\n\n    alloc_info.allocationSize = mem_reqs.size;\n    alloc_info.memoryTypeIndex = nk_glfw3_find_memory_index(\n        dev->physical_device, mem_reqs.memoryTypeBits,\n        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n            VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\n    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL,\n                              &staging_buffer.memory);\n    NK_ASSERT(result == VK_SUCCESS);\n    result = vkBindBufferMemory(dev->logical_device, staging_buffer.buffer,\n                                staging_buffer.memory, 0);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    result = vkMapMemory(dev->logical_device, staging_buffer.memory, 0,\n                         alloc_info.allocationSize, 0, (void **)&data);\n    NK_ASSERT(result == VK_SUCCESS);\n    memcpy(data, image, width * height * 4);\n    vkUnmapMemory(dev->logical_device, staging_buffer.memory);\n\n    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));\n    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n    NK_ASSERT(dev->command_buffers_len > 0);\n    /*\n    use the same command buffer as for render as we are regenerating the\n    buffer during render anyway\n    */\n    command_buffer = dev->command_buffers[0];\n    result = vkBeginCommandBuffer(command_buffer, &begin_info);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&image_memory_barrier, 0, sizeof(VkImageMemoryBarrier));\n    image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n    image_memory_barrier.image = dev->font_image;\n    image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n    image_memory_barrier.subresourceRange.aspectMask =\n        VK_IMAGE_ASPECT_COLOR_BIT;\n    image_memory_barrier.subresourceRange.levelCount = 1;\n    image_memory_barrier.subresourceRange.layerCount = 1;\n    image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;\n\n    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\n                         VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,\n                         &image_memory_barrier);\n\n    memset(&buffer_copy_region, 0, sizeof(VkBufferImageCopy));\n    buffer_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    buffer_copy_region.imageSubresource.layerCount = 1;\n    buffer_copy_region.imageExtent.width = (uint32_t)width;\n    buffer_copy_region.imageExtent.height = (uint32_t)height;\n    buffer_copy_region.imageExtent.depth = 1;\n\n    vkCmdCopyBufferToImage(\n        command_buffer, staging_buffer.buffer, dev->font_image,\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_copy_region);\n\n    memset(&image_shader_memory_barrier, 0, sizeof(VkImageMemoryBarrier));\n    image_shader_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n    image_shader_memory_barrier.image = dev->font_image;\n    image_shader_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_shader_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_shader_memory_barrier.oldLayout =\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n    image_shader_memory_barrier.newLayout =\n        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n    image_shader_memory_barrier.subresourceRange.aspectMask =\n        VK_IMAGE_ASPECT_COLOR_BIT;\n    image_shader_memory_barrier.subresourceRange.levelCount = 1;\n    image_shader_memory_barrier.subresourceRange.layerCount = 1;\n    image_shader_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,\n    image_shader_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,\n\n    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,\n                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0,\n                         NULL, 1, &image_shader_memory_barrier);\n\n    result = vkEndCommandBuffer(command_buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&fence_create, 0, sizeof(VkFenceCreateInfo));\n    fence_create.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;\n\n    result = vkCreateFence(dev->logical_device, &fence_create, NULL, &fence);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&submit_info, 0, sizeof(VkSubmitInfo));\n    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n    submit_info.commandBufferCount = 1;\n    submit_info.pCommandBuffers = &command_buffer;\n\n    result = vkQueueSubmit(graphics_queue, 1, &submit_info, fence);\n    NK_ASSERT(result == VK_SUCCESS);\n    result =\n        vkWaitForFences(dev->logical_device, 1, &fence, VK_TRUE, UINT64_MAX);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkDestroyFence(dev->logical_device, fence, NULL);\n\n    vkFreeMemory(dev->logical_device, staging_buffer.memory, NULL);\n    vkDestroyBuffer(dev->logical_device, staging_buffer.buffer, NULL);\n\n    memset(&image_view_info, 0, sizeof(VkImageViewCreateInfo));\n    image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n    image_view_info.image = dev->font_image;\n    image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n    image_view_info.format = image_info.format;\n    image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    image_view_info.subresourceRange.layerCount = 1;\n    image_view_info.subresourceRange.levelCount = 1;\n\n    result = vkCreateImageView(dev->logical_device, &image_view_info, NULL,\n                               &dev->font_image_view);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_glfw3_destroy_render_resources(struct nk_glfw_device *dev) {\n    uint32_t i;\n\n    vkDestroyPipeline(dev->logical_device, dev->pipeline, NULL);\n    vkDestroyPipelineLayout(dev->logical_device, dev->pipeline_layout, NULL);\n    vkDestroyDescriptorSetLayout(dev->logical_device,\n                                 dev->texture_descriptor_set_layout, NULL);\n    vkDestroyDescriptorSetLayout(dev->logical_device,\n                                 dev->uniform_descriptor_set_layout, NULL);\n    vkDestroyDescriptorPool(dev->logical_device, dev->descriptor_pool, NULL);\n    for (i = 0; i < dev->framebuffers_len; i++) {\n        vkDestroyFramebuffer(dev->logical_device, dev->framebuffers[i], NULL);\n    }\n    free(dev->framebuffers);\n    dev->framebuffers_len = 0;\n    free(dev->texture_descriptor_sets);\n    dev->texture_descriptor_sets_len = 0;\n    vkDestroyRenderPass(dev->logical_device, dev->render_pass, NULL);\n}\n\nNK_API void nk_glfw3_resize(uint32_t framebuffer_width,\n                            uint32_t framebuffer_height) {\n    struct nk_glfw_device *dev = &glfw.vulkan;\n    glfwGetWindowSize(glfw.win, &glfw.width, &glfw.height);\n    glfwGetFramebufferSize(glfw.win, &glfw.display_width, &glfw.display_height);\n\n    nk_glfw3_destroy_render_resources(dev);\n    nk_glfw3_create_render_resources(dev, framebuffer_width,\n                                     framebuffer_height);\n}\n\nNK_API void nk_glfw3_device_destroy(void) {\n    struct nk_glfw_device *dev = &glfw.vulkan;\n\n    vkDeviceWaitIdle(dev->logical_device);\n\n    nk_glfw3_destroy_render_resources(dev);\n\n    vkFreeCommandBuffers(dev->logical_device, dev->command_pool,\n                         dev->command_buffers_len, dev->command_buffers);\n    vkDestroyCommandPool(dev->logical_device, dev->command_pool, NULL);\n    vkDestroySemaphore(dev->logical_device, dev->render_completed, NULL);\n\n    vkUnmapMemory(dev->logical_device, dev->vertex_memory);\n    vkUnmapMemory(dev->logical_device, dev->index_memory);\n    vkUnmapMemory(dev->logical_device, dev->uniform_memory);\n\n    vkFreeMemory(dev->logical_device, dev->vertex_memory, NULL);\n    vkFreeMemory(dev->logical_device, dev->index_memory, NULL);\n    vkFreeMemory(dev->logical_device, dev->uniform_memory, NULL);\n\n    vkDestroyBuffer(dev->logical_device, dev->vertex_buffer, NULL);\n    vkDestroyBuffer(dev->logical_device, dev->index_buffer, NULL);\n    vkDestroyBuffer(dev->logical_device, dev->uniform_buffer, NULL);\n\n    vkDestroySampler(dev->logical_device, dev->sampler, NULL);\n\n    vkFreeMemory(dev->logical_device, dev->font_memory, NULL);\n    vkDestroyImage(dev->logical_device, dev->font_image, NULL);\n    vkDestroyImageView(dev->logical_device, dev->font_image_view, NULL);\n\n    free(dev->command_buffers);\n    nk_buffer_free(&dev->cmds);\n}\n\nNK_API\nvoid nk_glfw3_shutdown(void) {\n    nk_font_atlas_clear(&glfw.atlas);\n    nk_free(&glfw.ctx);\n    nk_glfw3_device_destroy();\n    memset(&glfw, 0, sizeof(glfw));\n}\n\nNK_API void nk_glfw3_font_stash_begin(struct nk_font_atlas **atlas) {\n    nk_font_atlas_init_default(&glfw.atlas);\n    nk_font_atlas_begin(&glfw.atlas);\n    *atlas = &glfw.atlas;\n}\n\nNK_API void nk_glfw3_font_stash_end(VkQueue graphics_queue) {\n    struct nk_glfw_device *dev = &glfw.vulkan;\n\n    const void *image;\n    int w, h;\n    image = nk_font_atlas_bake(&glfw.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_glfw3_device_upload_atlas(graphics_queue, image, w, h);\n    nk_font_atlas_end(&glfw.atlas, nk_handle_ptr(dev->font_image_view),\n                      &dev->tex_null);\n    if (glfw.atlas.default_font) {\n        nk_style_set_font(&glfw.ctx, &glfw.atlas.default_font->handle);\n    }\n}\n\nNK_API void nk_glfw3_new_frame(void) {\n    int i;\n    double x, y;\n    struct nk_context *ctx = &glfw.ctx;\n    struct GLFWwindow *win = glfw.win;\n\n    /* update the timer */\n    float delta_time_now = (float)glfwGetTime();\n    glfw.ctx.delta_time_seconds = delta_time_now - glfw.delta_time_seconds_last;\n    glfw.delta_time_seconds_last = delta_time_now;\n\n    nk_input_begin(ctx);\n    for (i = 0; i < glfw.text_len; ++i)\n        nk_input_unicode(ctx, glfw.text[i]);\n\n#ifdef NK_GLFW_VULKAN_MOUSE_GRABBING\n    /* optional grabbing behavior */\n    if (ctx->input.mouse.grab)\n        glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);\n    else if (ctx->input.mouse.ungrab)\n        glfwSetInputMode(glfw.win, GLFW_CURSOR, GLFW_CURSOR_NORMAL);\n#endif\n\n    nk_input_key(ctx, NK_KEY_DEL,\n                 glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_ENTER,\n                 glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_BACKSPACE,\n                 glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_DOWN,\n                 glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_TEXT_START,\n                 glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_TEXT_END,\n                 glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SCROLL_START,\n                 glfwGetKey(win, GLFW_KEY_HOME) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SCROLL_END,\n                 glfwGetKey(win, GLFW_KEY_END) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SCROLL_DOWN,\n                 glfwGetKey(win, GLFW_KEY_PAGE_DOWN) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SCROLL_UP,\n                 glfwGetKey(win, GLFW_KEY_PAGE_UP) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_SHIFT,\n                 glfwGetKey(win, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS ||\n                     glfwGetKey(win, GLFW_KEY_RIGHT_SHIFT) == GLFW_PRESS);\n\n    if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||\n        glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {\n        nk_input_key(ctx, NK_KEY_COPY,\n                     glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_PASTE,\n                     glfwGetKey(win, GLFW_KEY_V) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_CUT,\n                     glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_TEXT_UNDO,\n                     glfwGetKey(win, GLFW_KEY_Z) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_TEXT_REDO,\n                     glfwGetKey(win, GLFW_KEY_R) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT,\n                     glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT,\n                     glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_TEXT_LINE_START,\n                     glfwGetKey(win, GLFW_KEY_B) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_TEXT_LINE_END,\n                     glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL,\n                     glfwGetKey(win, GLFW_KEY_A) == GLFW_PRESS);\n    } else {\n        nk_input_key(ctx, NK_KEY_LEFT,\n                     glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_RIGHT,\n                     glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_COPY, 0);\n        nk_input_key(ctx, NK_KEY_PASTE, 0);\n        nk_input_key(ctx, NK_KEY_CUT, 0);\n    }\n\n    glfwGetCursorPos(win, &x, &y);\n    nk_input_motion(ctx, (int)x, (int)y);\n#ifdef NK_GLFW_VULKAN_MOUSE_GRABBING\n    if (ctx->input.mouse.grabbed) {\n        glfwSetCursorPos(glfw.win, ctx->input.mouse.prev.x,\n                         ctx->input.mouse.prev.y);\n        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n    }\n#endif\n    nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y,\n                    glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) ==\n                        GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y,\n                    glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) ==\n                        GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y,\n                    glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) ==\n                        GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_DOUBLE, (int)glfw.double_click_pos.x,\n                    (int)glfw.double_click_pos.y, glfw.is_double_click_down);\n    nk_input_scroll(ctx, glfw.scroll);\n    nk_input_end(&glfw.ctx);\n    glfw.text_len = 0;\n    glfw.scroll = nk_vec2(0, 0);\n}\n\nNK_INTERN void update_texture_descriptor_set(\n    struct nk_glfw_device *dev,\n    struct nk_vulkan_texture_descriptor_set *texture_descriptor_set,\n    VkImageView image_view) {\n    VkDescriptorImageInfo descriptor_image_info;\n    VkWriteDescriptorSet descriptor_write;\n\n    texture_descriptor_set->image_view = image_view;\n\n    memset(&descriptor_image_info, 0, sizeof(VkDescriptorImageInfo));\n    descriptor_image_info.sampler = dev->sampler;\n    descriptor_image_info.imageView = texture_descriptor_set->image_view;\n    descriptor_image_info.imageLayout =\n        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n\n    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));\n    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n    descriptor_write.dstSet = texture_descriptor_set->descriptor_set;\n    descriptor_write.dstBinding = 0;\n    descriptor_write.dstArrayElement = 0;\n    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    descriptor_write.descriptorCount = 1;\n    descriptor_write.pImageInfo = &descriptor_image_info;\n\n    vkUpdateDescriptorSets(dev->logical_device, 1, &descriptor_write, 0, NULL);\n}\n\nNK_API\nVkSemaphore nk_glfw3_render(VkQueue graphics_queue, uint32_t buffer_index,\n                            VkSemaphore wait_semaphore,\n                            enum nk_anti_aliasing AA) {\n    struct nk_glfw_device *dev = &glfw.vulkan;\n    struct nk_buffer vbuf, ebuf;\n\n    struct Mat4f projection = {\n        {2.0f, 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f,\n         0.0f, -1.0f, 1.0f, 0.0f, 1.0f},\n    };\n\n    VkCommandBufferBeginInfo begin_info;\n    VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 0.0f}}};\n    VkRenderPassBeginInfo render_pass_begin_nfo;\n    VkCommandBuffer command_buffer;\n    VkResult result;\n    VkViewport viewport;\n\n    VkDeviceSize doffset = 0;\n    VkImageView current_texture = NULL;\n    uint32_t index_offset = 0;\n    VkRect2D scissor;\n    uint32_t wait_semaphore_count;\n    VkSemaphore *wait_semaphores;\n    VkPipelineStageFlags wait_stage =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    VkSubmitInfo submit_info;\n\n    projection.m[0] /= glfw.width;\n    projection.m[5] /= glfw.height;\n\n    memcpy(dev->mapped_uniform, &projection, sizeof(projection));\n\n    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));\n    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n    memset(&render_pass_begin_nfo, 0, sizeof(VkRenderPassBeginInfo));\n    render_pass_begin_nfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;\n    render_pass_begin_nfo.renderPass = dev->render_pass;\n    render_pass_begin_nfo.renderArea.extent.width = (uint32_t)glfw.width;\n    render_pass_begin_nfo.renderArea.extent.height = (uint32_t)glfw.height;\n    render_pass_begin_nfo.clearValueCount = 1;\n    render_pass_begin_nfo.pClearValues = &clear_value;\n    render_pass_begin_nfo.framebuffer = dev->framebuffers[buffer_index];\n\n    command_buffer = dev->command_buffers[buffer_index];\n\n    result = vkBeginCommandBuffer(command_buffer, &begin_info);\n    NK_ASSERT(result == VK_SUCCESS);\n    vkCmdBeginRenderPass(command_buffer, &render_pass_begin_nfo,\n                         VK_SUBPASS_CONTENTS_INLINE);\n\n    memset(&viewport, 0, sizeof(VkViewport));\n    viewport.width = (float)glfw.width;\n    viewport.height = (float)glfw.height;\n    viewport.maxDepth = 1.0f;\n    vkCmdSetViewport(command_buffer, 0, 1, &viewport);\n\n    vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                      dev->pipeline);\n    vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                            dev->pipeline_layout, 0, 1,\n                            &dev->uniform_descriptor_set, 0, NULL);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        /* load draw vertices & elements directly into vertex + element buffer\n         */\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] =\n                {{NK_VERTEX_POSITION, NK_FORMAT_FLOAT,\n                  NK_OFFSETOF(struct nk_glfw_vertex, position)},\n                 {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT,\n                  NK_OFFSETOF(struct nk_glfw_vertex, uv)},\n                 {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8,\n                  NK_OFFSETOF(struct nk_glfw_vertex, col)},\n                 {NK_VERTEX_LAYOUT_END}};\n            NK_MEMSET(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_glfw_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            nk_buffer_init_fixed(&vbuf, dev->mapped_vertex,\n                                 (size_t)dev->max_vertex_buffer);\n            nk_buffer_init_fixed(&ebuf, dev->mapped_index,\n                                 (size_t)dev->max_element_buffer);\n            nk_convert(&glfw.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n        }\n\n        /* iterate over and execute each draw command */\n\n        vkCmdBindVertexBuffers(command_buffer, 0, 1, &dev->vertex_buffer,\n                               &doffset);\n        vkCmdBindIndexBuffer(command_buffer, dev->index_buffer, 0,\n                             VK_INDEX_TYPE_UINT16);\n\n        nk_draw_foreach(cmd, &glfw.ctx, &dev->cmds) {\n            if (!cmd->texture.ptr) {\n                continue;\n            }\n            if (cmd->texture.ptr && cmd->texture.ptr != current_texture) {\n                int found = 0;\n                uint32_t i;\n                for (i = 0; i < dev->texture_descriptor_sets_len; i++) {\n                    if (dev->texture_descriptor_sets[i].image_view ==\n                        cmd->texture.ptr) {\n                        found = 1;\n                        break;\n                    }\n                }\n\n                if (!found) {\n                    update_texture_descriptor_set(\n                        dev, &dev->texture_descriptor_sets[i],\n                        (VkImageView)cmd->texture.ptr);\n                    dev->texture_descriptor_sets_len++;\n                }\n                vkCmdBindDescriptorSets(\n                    command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                    dev->pipeline_layout, 1, 1,\n                    &dev->texture_descriptor_sets[i].descriptor_set, 0, NULL);\n            }\n\n            if (!cmd->elem_count)\n                continue;\n\n            scissor.offset.x = (int32_t)(NK_MAX(cmd->clip_rect.x, 0.f));\n            scissor.offset.y = (int32_t)(NK_MAX(cmd->clip_rect.y, 0.f));\n            scissor.extent.width = (uint32_t)(cmd->clip_rect.w);\n            scissor.extent.height = (uint32_t)(cmd->clip_rect.h);\n            vkCmdSetScissor(command_buffer, 0, 1, &scissor);\n            vkCmdDrawIndexed(command_buffer, cmd->elem_count, 1, index_offset,\n                             0, 0);\n            index_offset += cmd->elem_count;\n        }\n        nk_clear(&glfw.ctx);\n    }\n\n    vkCmdEndRenderPass(command_buffer);\n    result = vkEndCommandBuffer(command_buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    if (wait_semaphore) {\n        wait_semaphore_count = 1;\n        wait_semaphores = &wait_semaphore;\n    } else {\n        wait_semaphore_count = 0;\n        wait_semaphores = NULL;\n    }\n\n    memset(&submit_info, 0, sizeof(VkSubmitInfo));\n    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n    submit_info.commandBufferCount = 1;\n    submit_info.pCommandBuffers = &command_buffer;\n    submit_info.pWaitDstStageMask = &wait_stage;\n    submit_info.waitSemaphoreCount = wait_semaphore_count;\n    submit_info.pWaitSemaphores = wait_semaphores;\n    submit_info.signalSemaphoreCount = 1;\n    submit_info.pSignalSemaphores = &dev->render_completed;\n\n    result = vkQueueSubmit(graphics_queue, 1, &submit_info, NULL);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    return dev->render_completed;\n}\n\nNK_API void nk_glfw3_char_callback(GLFWwindow *win, unsigned int codepoint) {\n    (void)win;\n    if (glfw.text_len < NK_GLFW_TEXT_MAX)\n        glfw.text[glfw.text_len++] = codepoint;\n}\n\nNK_API void nk_gflw3_scroll_callback(GLFWwindow *win, double xoff,\n                                     double yoff) {\n    (void)win;\n    (void)xoff;\n    glfw.scroll.x += (float)xoff;\n    glfw.scroll.y += (float)yoff;\n}\n\nNK_API void nk_glfw3_mouse_button_callback(GLFWwindow *window, int button,\n                                           int action, int mods) {\n    double x, y;\n    NK_UNUSED(mods);\n    if (button != GLFW_MOUSE_BUTTON_LEFT)\n        return;\n    glfwGetCursorPos(window, &x, &y);\n    if (action == GLFW_PRESS) {\n        double dt = glfwGetTime() - glfw.last_button_click;\n        if (dt > NK_GLFW_DOUBLE_CLICK_LO && dt < NK_GLFW_DOUBLE_CLICK_HI) {\n            glfw.is_double_click_down = nk_true;\n            glfw.double_click_pos = nk_vec2((float)x, (float)y);\n        }\n        glfw.last_button_click = glfwGetTime();\n    } else\n        glfw.is_double_click_down = nk_false;\n}\n\nNK_INTERN void nk_glfw3_clipboard_paste(nk_handle usr,\n                                        struct nk_text_edit *edit) {\n    const char *text = glfwGetClipboardString(glfw.win);\n    if (text)\n        nk_textedit_paste(edit, text, nk_strlen(text));\n    (void)usr;\n}\n\nNK_INTERN void nk_glfw3_clipboard_copy(nk_handle usr, const char *text,\n                                       int len) {\n    char *str = 0;\n    (void)usr;\n    if (!len)\n        return;\n    str = (char *)malloc((size_t)len + 1);\n    if (!str)\n        return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n    glfwSetClipboardString(glfw.win, str);\n    free(str);\n}\n\nNK_API struct nk_context *\nnk_glfw3_init(GLFWwindow *win, VkDevice logical_device,\n              VkPhysicalDevice physical_device,\n              uint32_t graphics_queue_family_index, VkImageView *image_views,\n              uint32_t image_views_len, VkFormat color_format,\n              enum nk_glfw_init_state init_state,\n              VkDeviceSize max_vertex_buffer, VkDeviceSize max_element_buffer) {\n    memset(&glfw, 0, sizeof(struct nk_glfw));\n    glfw.win = win;\n    if (init_state == NK_GLFW3_INSTALL_CALLBACKS) {\n        glfwSetScrollCallback(win, nk_gflw3_scroll_callback);\n        glfwSetCharCallback(win, nk_glfw3_char_callback);\n        glfwSetMouseButtonCallback(win, nk_glfw3_mouse_button_callback);\n    }\n    nk_init_default(&glfw.ctx, 0);\n    glfw.ctx.clip.copy = nk_glfw3_clipboard_copy;\n    glfw.ctx.clip.paste = nk_glfw3_clipboard_paste;\n    glfw.ctx.clip.userdata = nk_handle_ptr(0);\n    glfw.last_button_click = 0;\n\n    glfwGetWindowSize(win, &glfw.width, &glfw.height);\n    glfwGetFramebufferSize(win, &glfw.display_width, &glfw.display_height);\n\n    nk_glfw3_device_create(logical_device, physical_device,\n                           graphics_queue_family_index, image_views,\n                           image_views_len, color_format, max_vertex_buffer,\n                           max_element_buffer, (uint32_t)glfw.display_width,\n                           (uint32_t)glfw.display_height);\n\n    glfw.is_double_click_down = nk_false;\n    glfw.double_click_pos = nk_vec2(0, 0);\n\n    return &glfw.ctx;\n}\n\n#endif\n"
  },
  {
    "path": "demo/glfw_vulkan/src/nuklearshaders/nuklear.frag",
    "content": "#version 450\n#extension GL_ARB_separate_shader_objects : enable\n\nlayout(binding = 0, set = 1) uniform sampler2D currentTexture;\n\nlayout(location = 0) in vec4 fragColor;\nlayout(location = 1) in vec2 fragUv;\nlayout(location = 0) out vec4 outColor;\n\nvoid main() {\n    vec4 texColor = texture(currentTexture, fragUv);\n    outColor = fragColor * texColor;\n}\n"
  },
  {
    "path": "demo/glfw_vulkan/src/nuklearshaders/nuklear.vert",
    "content": "#version 450\n#extension GL_ARB_separate_shader_objects : enable\n\nout gl_PerVertex {\n    vec4 gl_Position;\n};\n\nlayout(binding = 0) uniform UniformBufferObject {\n    mat4 projection;\n} ubo;\n\nlayout(location = 0) in vec2 position;\nlayout(location = 1) in vec2 uv;\nlayout(location = 2) in uvec4 color;\nlayout(location = 0) out vec4 fragColor;\nlayout(location = 1) out vec2 fragUv;\n\nvoid main() {\n    gl_Position = ubo.projection * vec4(position, 0.0, 1.0);\n    gl_Position.y = -gl_Position.y;\n    fragColor = vec4(color[0]/255.0, color[1]/255.0, color[2]/255.0, color[3]/255.0);\n    fragUv = uv;\n}\n"
  },
  {
    "path": "demo/rawfb/nuklear_rawfb.h",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2016-2017 Patrick Rudolph <siro@das-labor.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n*/\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n\n#ifndef NK_RAWFB_H_\n#define NK_RAWFB_H_\n\nstruct rawfb_context;\n\nstruct rawfb_pl {\n    unsigned char bytesPerPixel;\n    unsigned char rshift, gshift, bshift, ashift;\n    unsigned char rloss, gloss, bloss, aloss;\n};\n\n/* All functions are thread-safe */\nNK_API struct rawfb_context *nk_rawfb_init(void *fb, void *tex_mem, const unsigned int w, const unsigned int h, const unsigned int pitch, const struct rawfb_pl pl);\nNK_API void                  nk_rawfb_render(const struct rawfb_context *rawfb, const struct nk_color clear, const unsigned char enable_clear);\nNK_API void                  nk_rawfb_shutdown(struct rawfb_context *rawfb);\nNK_API void                  nk_rawfb_resize_fb(struct rawfb_context *rawfb, void *fb, const unsigned int w, const unsigned int h, const unsigned int pitch, const struct rawfb_pl pl);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_RAWFB_IMPLEMENTATION\n#include <string.h>\n#include <stdlib.h>\n#include <assert.h>\n\nstruct rawfb_image {\n    void *pixels;\n    int w, h, pitch;\n    struct rawfb_pl pl;\n};\nstruct rawfb_context {\n    struct nk_context ctx;\n    struct nk_rect scissors;\n    struct rawfb_image fb;\n    struct rawfb_image font_tex;\n    struct nk_font_atlas atlas;\n};\ntypedef unsigned int rawfb_color;\n\n#ifndef MIN\n#define MIN(a,b) ((a) < (b) ? (a) : (b))\n#endif\n#ifndef MAX\n#define MAX(a,b) ((a) < (b) ? (b) : (a))\n#endif\n\nstatic rawfb_color\nnk_rawfb_color2int(const struct nk_color c, const struct rawfb_pl *pl)\n{\n    unsigned int res = 0;\n\n    res |= (c.r >> pl->rloss) << pl->rshift;\n    res |= (c.g >> pl->gloss) << pl->gshift;\n    res |= (c.b >> pl->bloss) << pl->bshift;\n    res |= (c.a >> pl->aloss) << pl->ashift;\n\n    return (res);\n}\n\nstatic struct nk_color\nnk_rawfb_int2color(const rawfb_color i, const struct rawfb_pl *pl)\n{\n    struct nk_color col = {0,0,0,0};\n\n    col.r = (pl->rloss == 8) ? 0xff : ((i >> pl->rshift) << pl->rloss) & 0xff;\n    col.g = (pl->gloss == 8) ? 0xff : ((i >> pl->gshift) << pl->gloss) & 0xff;\n    col.b = (pl->bloss == 8) ? 0xff : ((i >> pl->bshift) << pl->bloss) & 0xff;\n    col.a = (pl->aloss == 8) ? 0xff : ((i >> pl->ashift) << pl->aloss) & 0xff;\n\n    return col;\n}\n\nstatic void\nnk_rawfb_ctx_setpixel(const struct rawfb_context *rawfb,\n    const short x0, const short y0, const rawfb_color col)\n{\n    unsigned char *pixels = rawfb->fb.pixels;\n\n    pixels += y0 * rawfb->fb.pitch;\n\n    if (y0 < rawfb->scissors.h && y0 >= rawfb->scissors.y &&\n        x0 >= rawfb->scissors.x && x0 < rawfb->scissors.w) {\n\n        if (rawfb->fb.pl.bytesPerPixel == sizeof(unsigned int)) {\n            *((unsigned int *)pixels + x0) = col;\n        } else if (rawfb->fb.pl.bytesPerPixel == sizeof(unsigned short)) {\n            *((unsigned short *)pixels + x0) = col;\n        } else {\n            *((unsigned char *)pixels + x0) = col;\n        }\n    }\n}\n\nstatic void\nnk_rawfb_line_horizontal(const struct rawfb_context *rawfb,\n    const short x0, const short y, const short x1, const rawfb_color col)\n{\n    /* This function is called the most. Try to optimize it a bit...\n     * It does not check for scissors or image borders.\n     * The caller has to make sure it does no exceed bounds. */\n    unsigned int i, n;\n    unsigned char c[16 * 4];\n    unsigned char *pixels = rawfb->fb.pixels;\n    unsigned int bpp = rawfb->fb.pl.bytesPerPixel;\n\n    pixels += (y * rawfb->fb.pitch) + (x0 * bpp);\n\n    n = (x1 - x0) * bpp;\n    if (bpp == sizeof(unsigned int)) {\n        for (i = 0; i < sizeof(c) / bpp; i++)\n            ((unsigned int *)c)[i] = col;\n    } else if (bpp == sizeof(unsigned short)) {\n        for (i = 0; i < sizeof(c) / bpp; i++)\n            ((unsigned short *)c)[i] = col;\n    } else {\n        for (i = 0; i < sizeof(c) / bpp; i++)\n            ((unsigned char *)c)[i] = col;\n    }\n\n    while (n > sizeof(c)) {\n        memcpy((void*)pixels, c, sizeof(c));\n        n -= sizeof(c); pixels += sizeof(c);\n    } for (i = 0; i < n; i++)\n        pixels[i] = c[i];\n}\n\nstatic void\nnk_rawfb_img_setpixel(const struct rawfb_image *img,\n    const int x0, const int y0, const struct nk_color col)\n{\n    unsigned int c = nk_rawfb_color2int(col, &img->pl);\n    unsigned char *ptr;\n    NK_ASSERT(img);\n    if (y0 < img->h && y0 >= 0 && x0 >= 0 && x0 < img->w) {\n        ptr = (unsigned char *)img->pixels + (img->pitch * y0);\n\n        if (img->pl.bytesPerPixel == sizeof(unsigned int)) {\n            ((unsigned int *)ptr)[x0] = c;\n        } else if (img->pl.bytesPerPixel == sizeof(unsigned short)) {\n            ((unsigned short *)ptr)[x0] = c;\n        } else {\n            ((unsigned char *)ptr)[x0] = c;\n        }\n    }\n}\n\nstatic struct nk_color\nnk_rawfb_img_getpixel(const struct rawfb_image *img, const int x0, const int y0)\n{\n    struct nk_color col = {0, 0, 0, 0};\n    unsigned char *ptr;\n    unsigned int pixel;\n    NK_ASSERT(img);\n    if (y0 < img->h && y0 >= 0 && x0 >= 0 && x0 < img->w) {\n        ptr = (unsigned char *)img->pixels + (img->pitch * y0);\n\n        if (img->pl.bytesPerPixel == sizeof(unsigned int)) {\n            pixel = ((unsigned int *)ptr)[x0];\n            col = nk_rawfb_int2color(pixel, &img->pl);\n        } else if (img->pl.bytesPerPixel == sizeof(unsigned short)) {\n            pixel = ((unsigned short *)ptr)[x0];\n            col = nk_rawfb_int2color(pixel, &img->pl);\n        } else {\n            pixel = ((unsigned char *)ptr)[x0];\n            col = nk_rawfb_int2color(pixel, &img->pl);\n        }\n    } return col;\n}\nstatic void\nnk_rawfb_img_blendpixel(const struct rawfb_image *img,\n    const int x0, const int y0, struct nk_color col)\n{\n    struct nk_color col2;\n    unsigned char inv_a;\n    if (col.a == 0)\n        return;\n\n    inv_a = 0xff - col.a;\n    col2 = nk_rawfb_img_getpixel(img, x0, y0);\n    col.r = (col.r * col.a + col2.r * inv_a) >> 8;\n    col.g = (col.g * col.a + col2.g * inv_a) >> 8;\n    col.b = (col.b * col.a + col2.b * inv_a) >> 8;\n    nk_rawfb_img_setpixel(img, x0, y0, col);\n}\n\nstatic void\nnk_rawfb_scissor(struct rawfb_context *rawfb,\n                 const float x,\n                 const float y,\n                 const float w,\n                 const float h)\n{\n    rawfb->scissors.x = MIN(MAX(x, 0), rawfb->fb.w);\n    rawfb->scissors.y = MIN(MAX(y, 0), rawfb->fb.h);\n    rawfb->scissors.w = MIN(MAX(w + x, 0), rawfb->fb.w);\n    rawfb->scissors.h = MIN(MAX(h + y, 0), rawfb->fb.h);\n}\n\nstatic void\nnk_rawfb_stroke_line(const struct rawfb_context *rawfb,\n    short x0, short y0, short x1, short y1,\n    const unsigned int line_thickness, const rawfb_color col)\n{\n    short tmp;\n    int dy, dx, stepx, stepy;\n\n    NK_UNUSED(line_thickness);\n\n    dy = y1 - y0;\n    dx = x1 - x0;\n\n    /* fast path */\n    if (dy == 0) {\n        if (dx == 0 || y0 >= rawfb->scissors.h || y0 < rawfb->scissors.y)\n            return;\n\n        if (dx < 0) {\n            /* swap x0 and x1 */\n            tmp = x1;\n            x1 = x0;\n            x0 = tmp;\n        }\n        x1 = MIN(rawfb->scissors.w, x1);\n        x0 = MIN(rawfb->scissors.w, x0);\n        x1 = MAX(rawfb->scissors.x, x1);\n        x0 = MAX(rawfb->scissors.x, x0);\n        nk_rawfb_line_horizontal(rawfb, x0, y0, x1, col);\n        return;\n    }\n    if (dy < 0) {\n        dy = -dy;\n        stepy = -1;\n    } else stepy = 1;\n\n    if (dx < 0) {\n        dx = -dx;\n        stepx = -1;\n    } else stepx = 1;\n\n    dy <<= 1;\n    dx <<= 1;\n\n    nk_rawfb_ctx_setpixel(rawfb, x0, y0, col);\n    if (dx > dy) {\n        int fraction = dy - (dx >> 1);\n        while (x0 != x1) {\n            if (fraction >= 0) {\n                y0 += stepy;\n                fraction -= dx;\n            }\n            x0 += stepx;\n            fraction += dy;\n            nk_rawfb_ctx_setpixel(rawfb, x0, y0, col);\n        }\n    } else {\n        int fraction = dx - (dy >> 1);\n        while (y0 != y1) {\n            if (fraction >= 0) {\n                x0 += stepx;\n                fraction -= dy;\n            }\n            y0 += stepy;\n            fraction += dx;\n            nk_rawfb_ctx_setpixel(rawfb, x0, y0, col);\n        }\n    }\n}\n\nstatic void\nnk_rawfb_fill_polygon(const struct rawfb_context *rawfb,\n    const struct nk_vec2i *pnts, int count, const rawfb_color col)\n{\n    int i = 0;\n    #define MAX_POINTS 64\n    int left = 10000, top = 10000, bottom = 0, right = 0;\n    int nodes, nodeX[MAX_POINTS], pixelX, pixelY, j, swap ;\n\n    if (count == 0) return;\n    if (count > MAX_POINTS)\n        count = MAX_POINTS;\n\n    /* Get polygon dimensions */\n    for (i = 0; i < count; i++) {\n        if (left > pnts[i].x)\n            left = pnts[i].x;\n        if (right < pnts[i].x)\n            right = pnts[i].x;\n        if (top > pnts[i].y)\n            top = pnts[i].y;\n        if (bottom < pnts[i].y)\n            bottom = pnts[i].y;\n    } bottom++; right++;\n\n    /* Polygon scanline algorithm released under public-domain by Darel Rex Finley, 2007 */\n    /*  Loop through the rows of the image. */\n    for (pixelY = top; pixelY < bottom; pixelY ++) {\n        nodes = 0; /*  Build a list of nodes. */\n        j = count - 1;\n        for (i = 0; i < count; i++) {\n            if (((pnts[i].y < pixelY) && (pnts[j].y >= pixelY)) ||\n                ((pnts[j].y < pixelY) && (pnts[i].y >= pixelY))) {\n                nodeX[nodes++]= (int)((float)pnts[i].x\n                     + ((float)pixelY - (float)pnts[i].y) / ((float)pnts[j].y - (float)pnts[i].y)\n                     * ((float)pnts[j].x - (float)pnts[i].x));\n            } j = i;\n        }\n\n        /*  Sort the nodes, via a simple “Bubble” sort. */\n        i = 0;\n        while (i < nodes - 1) {\n            if (nodeX[i] > nodeX[i+1]) {\n                swap = nodeX[i];\n                nodeX[i] = nodeX[i+1];\n                nodeX[i+1] = swap;\n                if (i) i--;\n            } else i++;\n        }\n        /*  Fill the pixels between node pairs. */\n        for (i = 0; i < nodes; i += 2) {\n            if (nodeX[i+0] >= right) break;\n            if (nodeX[i+1] > left) {\n                if (nodeX[i+0] < left) nodeX[i+0] = left ;\n                if (nodeX[i+1] > right) nodeX[i+1] = right;\n                for (pixelX = nodeX[i]; pixelX < nodeX[i + 1]; pixelX++)\n                    nk_rawfb_ctx_setpixel(rawfb, pixelX, pixelY, col);\n            }\n        }\n    }\n    #undef MAX_POINTS\n}\n\nstatic void\nnk_rawfb_stroke_arc(const struct rawfb_context *rawfb,\n    short x0, short y0, short w, short h, const short s,\n    const short line_thickness, const rawfb_color col)\n{\n    /* Bresenham's ellipses - modified to draw one quarter */\n    const int a2 = (w * w) / 4;\n    const int b2 = (h * h) / 4;\n    const int fa2 = 4 * a2, fb2 = 4 * b2;\n    int x, y, sigma;\n\n    NK_UNUSED(line_thickness);\n\n    if (s != 0 && s != 90 && s != 180 && s != 270) return;\n    if (w < 1 || h < 1) return;\n\n    /* Convert upper left to center */\n    h = (h + 1) / 2;\n    w = (w + 1) / 2;\n    x0 += w; y0 += h;\n\n    /* First half */\n    for (x = 0, y = h, sigma = 2*b2+a2*(1-2*h); b2*x <= a2*y; x++) {\n        if (s == 180)\n            nk_rawfb_ctx_setpixel(rawfb, x0 + x, y0 + y, col);\n        else if (s == 270)\n            nk_rawfb_ctx_setpixel(rawfb, x0 - x, y0 + y, col);\n        else if (s == 0)\n            nk_rawfb_ctx_setpixel(rawfb, x0 + x, y0 - y, col);\n        else if (s == 90)\n            nk_rawfb_ctx_setpixel(rawfb, x0 - x, y0 - y, col);\n        if (sigma >= 0) {\n            sigma += fa2 * (1 - y);\n            y--;\n        } sigma += b2 * ((4 * x) + 6);\n    }\n\n    /* Second half */\n    for (x = w, y = 0, sigma = 2*a2+b2*(1-2*w); a2*y <= b2*x; y++) {\n        if (s == 180)\n            nk_rawfb_ctx_setpixel(rawfb, x0 + x, y0 + y, col);\n        else if (s == 270)\n            nk_rawfb_ctx_setpixel(rawfb, x0 - x, y0 + y, col);\n        else if (s == 0)\n            nk_rawfb_ctx_setpixel(rawfb, x0 + x, y0 - y, col);\n        else if (s == 90)\n            nk_rawfb_ctx_setpixel(rawfb, x0 - x, y0 - y, col);\n        if (sigma >= 0) {\n            sigma += fb2 * (1 - x);\n            x--;\n        } sigma += a2 * ((4 * y) + 6);\n    }\n}\n\nstatic void\nnk_rawfb_fill_arc(const struct rawfb_context *rawfb, short x0, short y0,\n    short w, short h, const short s, const rawfb_color col)\n{\n    /* Bresenham's ellipses - modified to fill one quarter */\n    const int a2 = (w * w) / 4;\n    const int b2 = (h * h) / 4;\n    const int fa2 = 4 * a2, fb2 = 4 * b2;\n    int x, y, sigma;\n    struct nk_vec2i pnts[3];\n    if (w < 1 || h < 1) return;\n    if (s != 0 && s != 90 && s != 180 && s != 270)\n        return;\n\n    /* Convert upper left to center */\n    h = (h + 1) / 2;\n    w = (w + 1) / 2;\n    x0 += w;\n    y0 += h;\n\n    pnts[0].x = x0;\n    pnts[0].y = y0;\n    pnts[2].x = x0;\n    pnts[2].y = y0;\n\n    /* First half */\n    for (x = 0, y = h, sigma = 2*b2+a2*(1-2*h); b2*x <= a2*y; x++) {\n        if (s == 180) {\n            pnts[1].x = x0 + x; pnts[1].y = y0 + y;\n        } else if (s == 270) {\n            pnts[1].x = x0 - x; pnts[1].y = y0 + y;\n        } else if (s == 0) {\n            pnts[1].x = x0 + x; pnts[1].y = y0 - y;\n        } else if (s == 90) {\n            pnts[1].x = x0 - x; pnts[1].y = y0 - y;\n        }\n        nk_rawfb_fill_polygon(rawfb, pnts, 3, col);\n        pnts[2] = pnts[1];\n        if (sigma >= 0) {\n            sigma += fa2 * (1 - y);\n            y--;\n        } sigma += b2 * ((4 * x) + 6);\n    }\n\n    /* Second half */\n    for (x = w, y = 0, sigma = 2*a2+b2*(1-2*w); a2*y <= b2*x; y++) {\n        if (s == 180) {\n            pnts[1].x = x0 + x; pnts[1].y = y0 + y;\n        } else if (s == 270) {\n            pnts[1].x = x0 - x; pnts[1].y = y0 + y;\n        } else if (s == 0) {\n            pnts[1].x = x0 + x; pnts[1].y = y0 - y;\n        } else if (s == 90) {\n            pnts[1].x = x0 - x; pnts[1].y = y0 - y;\n        }\n        nk_rawfb_fill_polygon(rawfb, pnts, 3, col);\n        pnts[2] = pnts[1];\n        if (sigma >= 0) {\n            sigma += fb2 * (1 - x);\n            x--;\n        } sigma += a2 * ((4 * y) + 6);\n    }\n}\n\nstatic void\nnk_rawfb_stroke_rect(const struct rawfb_context *rawfb,\n    const short x, const short y, const short w, const short h,\n    const short r, const short line_thickness, const rawfb_color col)\n{\n    if (r == 0) {\n        nk_rawfb_stroke_line(rawfb, x, y, x + w, y, line_thickness, col);\n        nk_rawfb_stroke_line(rawfb, x, y + h, x + w, y + h, line_thickness, col);\n        nk_rawfb_stroke_line(rawfb, x, y, x, y + h, line_thickness, col);\n        nk_rawfb_stroke_line(rawfb, x + w, y, x + w, y + h, line_thickness, col);\n    } else {\n        const short xc = x + r;\n        const short yc = y + r;\n        const short wc = (short)(w - 2 * r);\n        const short hc = (short)(h - 2 * r);\n\n        nk_rawfb_stroke_line(rawfb, xc, y, xc + wc, y, line_thickness, col);\n        nk_rawfb_stroke_line(rawfb, x + w, yc, x + w, yc + hc, line_thickness, col);\n        nk_rawfb_stroke_line(rawfb, xc, y + h, xc + wc, y + h, line_thickness, col);\n        nk_rawfb_stroke_line(rawfb, x, yc, x, yc + hc, line_thickness, col);\n\n        nk_rawfb_stroke_arc(rawfb, xc + wc - r, y,\n                (unsigned)r*2, (unsigned)r*2, 0 , line_thickness, col);\n        nk_rawfb_stroke_arc(rawfb, x, y,\n                (unsigned)r*2, (unsigned)r*2, 90 , line_thickness, col);\n        nk_rawfb_stroke_arc(rawfb, x, yc + hc - r,\n                (unsigned)r*2, (unsigned)r*2, 270 , line_thickness, col);\n        nk_rawfb_stroke_arc(rawfb, xc + wc - r, yc + hc - r,\n                (unsigned)r*2, (unsigned)r*2, 180 , line_thickness, col);\n    }\n}\n\nstatic void\nnk_rawfb_fill_rect(const struct rawfb_context *rawfb,\n    const short x, const short y, const short w, const short h,\n    const short r, const rawfb_color col)\n{\n    int i;\n    if (r == 0) {\n        for (i = 0; i < h; i++)\n            nk_rawfb_stroke_line(rawfb, x, y + i, x + w, y + i, 1, col);\n    } else {\n        const short xc = x + r;\n        const short yc = y + r;\n        const short wc = (short)(w - 2 * r);\n        const short hc = (short)(h - 2 * r);\n\n        struct nk_vec2i pnts[12];\n        pnts[0].x = x;\n        pnts[0].y = yc;\n        pnts[1].x = xc;\n        pnts[1].y = yc;\n        pnts[2].x = xc;\n        pnts[2].y = y;\n\n        pnts[3].x = xc + wc;\n        pnts[3].y = y;\n        pnts[4].x = xc + wc;\n        pnts[4].y = yc;\n        pnts[5].x = x + w;\n        pnts[5].y = yc;\n\n        pnts[6].x = x + w;\n        pnts[6].y = yc + hc;\n        pnts[7].x = xc + wc;\n        pnts[7].y = yc + hc;\n        pnts[8].x = xc + wc;\n        pnts[8].y = y + h;\n\n        pnts[9].x = xc;\n        pnts[9].y = y + h;\n        pnts[10].x = xc;\n        pnts[10].y = yc + hc;\n        pnts[11].x = x;\n        pnts[11].y = yc + hc;\n\n        nk_rawfb_fill_polygon(rawfb, pnts, 12, col);\n\n        nk_rawfb_fill_arc(rawfb, xc + wc - r, y,\n                (unsigned)r*2, (unsigned)r*2, 0 , col);\n        nk_rawfb_fill_arc(rawfb, x, y,\n                (unsigned)r*2, (unsigned)r*2, 90 , col);\n        nk_rawfb_fill_arc(rawfb, x, yc + hc - r,\n                (unsigned)r*2, (unsigned)r*2, 270 , col);\n        nk_rawfb_fill_arc(rawfb, xc + wc - r, yc + hc - r,\n                (unsigned)r*2, (unsigned)r*2, 180 , col);\n    }\n}\n\nNK_API void\nnk_rawfb_draw_rect_multi_color(const struct rawfb_context *rawfb,\n    const short x, const short y, const short w, const short h, struct nk_color tl,\n    struct nk_color tr, struct nk_color br, struct nk_color bl)\n{\n    int i, j;\n    struct nk_color *edge_buf;\n    struct nk_color *edge_t;\n    struct nk_color *edge_b;\n    struct nk_color *edge_l;\n    struct nk_color *edge_r;\n    struct nk_color pixel;\n\n    edge_buf = malloc(((2*w) + (2*h)) * sizeof(struct nk_color));\n    if (edge_buf == NULL)\n        return;\n\n    edge_t = edge_buf;\n    edge_b = edge_buf + w;\n    edge_l = edge_buf + (w*2);\n    edge_r = edge_buf + (w*2) + h;\n\n    /* Top and bottom edge gradients */\n    for (i=0; i<w; i++)\n    {\n        edge_t[i].r = (((((float)tr.r - tl.r)/(w-1))*i) + 0.5) + tl.r;\n        edge_t[i].g = (((((float)tr.g - tl.g)/(w-1))*i) + 0.5) + tl.g;\n        edge_t[i].b = (((((float)tr.b - tl.b)/(w-1))*i) + 0.5) + tl.b;\n        edge_t[i].a = (((((float)tr.a - tl.a)/(w-1))*i) + 0.5) + tl.a;\n\n        edge_b[i].r = (((((float)br.r - bl.r)/(w-1))*i) + 0.5) + bl.r;\n        edge_b[i].g = (((((float)br.g - bl.g)/(w-1))*i) + 0.5) + bl.g;\n        edge_b[i].b = (((((float)br.b - bl.b)/(w-1))*i) + 0.5) + bl.b;\n        edge_b[i].a = (((((float)br.a - bl.a)/(w-1))*i) + 0.5) + bl.a;\n    }\n\n    /* Left and right edge gradients */\n    for (i=0; i<h; i++)\n    {\n        edge_l[i].r = (((((float)bl.r - tl.r)/(h-1))*i) + 0.5) + tl.r;\n        edge_l[i].g = (((((float)bl.g - tl.g)/(h-1))*i) + 0.5) + tl.g;\n        edge_l[i].b = (((((float)bl.b - tl.b)/(h-1))*i) + 0.5) + tl.b;\n        edge_l[i].a = (((((float)bl.a - tl.a)/(h-1))*i) + 0.5) + tl.a;\n\n        edge_r[i].r = (((((float)br.r - tr.r)/(h-1))*i) + 0.5) + tr.r;\n        edge_r[i].g = (((((float)br.g - tr.g)/(h-1))*i) + 0.5) + tr.g;\n        edge_r[i].b = (((((float)br.b - tr.b)/(h-1))*i) + 0.5) + tr.b;\n        edge_r[i].a = (((((float)br.a - tr.a)/(h-1))*i) + 0.5) + tr.a;\n    }\n\n    for (i=0; i<h; i++) {\n        for (j=0; j<w; j++) {\n            if (i==0) {\n                nk_rawfb_img_blendpixel(&rawfb->fb, x+j, y+i, edge_t[j]);\n            } else if (i==h-1) {\n                nk_rawfb_img_blendpixel(&rawfb->fb, x+j, y+i, edge_b[j]);\n            } else {\n                if (j==0) {\n                    nk_rawfb_img_blendpixel(&rawfb->fb, x+j, y+i, edge_l[i]);\n                } else if (j==w-1) {\n                    nk_rawfb_img_blendpixel(&rawfb->fb, x+j, y+i, edge_r[i]);\n                } else {\n                    pixel.r = (((((float)edge_r[i].r - edge_l[i].r)/(w-1))*j) + 0.5) + edge_l[i].r;\n                    pixel.g = (((((float)edge_r[i].g - edge_l[i].g)/(w-1))*j) + 0.5) + edge_l[i].g;\n                    pixel.b = (((((float)edge_r[i].b - edge_l[i].b)/(w-1))*j) + 0.5) + edge_l[i].b;\n                    pixel.a = (((((float)edge_r[i].a - edge_l[i].a)/(w-1))*j) + 0.5) + edge_l[i].a;\n                    nk_rawfb_img_blendpixel(&rawfb->fb, x+j, y+i, pixel);\n                }\n            }\n        }\n    }\n\n    free(edge_buf);\n}\n\nstatic void\nnk_rawfb_fill_triangle(const struct rawfb_context *rawfb,\n    const short x0, const short y0, const short x1, const short y1,\n    const short x2, const short y2, const rawfb_color col)\n{\n    struct nk_vec2i pnts[3];\n    pnts[0].x = x0;\n    pnts[0].y = y0;\n    pnts[1].x = x1;\n    pnts[1].y = y1;\n    pnts[2].x = x2;\n    pnts[2].y = y2;\n    nk_rawfb_fill_polygon(rawfb, pnts, 3, col);\n}\n\nstatic void\nnk_rawfb_stroke_triangle(const struct rawfb_context *rawfb,\n    const short x0, const short y0, const short x1, const short y1,\n    const short x2, const short y2, const unsigned short line_thickness,\n    const rawfb_color col)\n{\n    nk_rawfb_stroke_line(rawfb, x0, y0, x1, y1, line_thickness, col);\n    nk_rawfb_stroke_line(rawfb, x1, y1, x2, y2, line_thickness, col);\n    nk_rawfb_stroke_line(rawfb, x2, y2, x0, y0, line_thickness, col);\n}\n\nstatic void\nnk_rawfb_stroke_polygon(const struct rawfb_context *rawfb,\n    const struct nk_vec2i *pnts, const int count,\n    const unsigned short line_thickness, const rawfb_color col)\n{\n    int i;\n    for (i = 1; i < count; ++i)\n        nk_rawfb_stroke_line(rawfb, pnts[i-1].x, pnts[i-1].y, pnts[i].x,\n                pnts[i].y, line_thickness, col);\n    nk_rawfb_stroke_line(rawfb, pnts[count-1].x, pnts[count-1].y,\n            pnts[0].x, pnts[0].y, line_thickness, col);\n}\n\nstatic void\nnk_rawfb_stroke_polyline(const struct rawfb_context *rawfb,\n    const struct nk_vec2i *pnts, const int count,\n    const unsigned short line_thickness, const rawfb_color col)\n{\n    int i;\n    for (i = 0; i < count-1; ++i)\n        nk_rawfb_stroke_line(rawfb, pnts[i].x, pnts[i].y,\n                 pnts[i+1].x, pnts[i+1].y, line_thickness, col);\n}\n\nstatic void\nnk_rawfb_fill_circle(const struct rawfb_context *rawfb,\n    short x0, short y0, short w, short h, const rawfb_color col)\n{\n    /* Bresenham's ellipses */\n    const int a2 = (w * w) / 4;\n    const int b2 = (h * h) / 4;\n    const int fa2 = 4 * a2, fb2 = 4 * b2;\n    int x, y, sigma;\n\n    /* Convert upper left to center */\n    h = (h + 1) / 2;\n    w = (w + 1) / 2;\n    x0 += w;\n    y0 += h;\n\n    /* First half */\n    for (x = 0, y = h, sigma = 2*b2+a2*(1-2*h); b2*x <= a2*y; x++) {\n        nk_rawfb_stroke_line(rawfb, x0 - x, y0 + y, x0 + x, y0 + y, 1, col);\n        nk_rawfb_stroke_line(rawfb, x0 - x, y0 - y, x0 + x, y0 - y, 1, col);\n        if (sigma >= 0) {\n            sigma += fa2 * (1 - y);\n            y--;\n        } sigma += b2 * ((4 * x) + 6);\n    }\n    /* Second half */\n    for (x = w, y = 0, sigma = 2*a2+b2*(1-2*w); a2*y <= b2*x; y++) {\n        nk_rawfb_stroke_line(rawfb, x0 - x, y0 + y, x0 + x, y0 + y, 1, col);\n        nk_rawfb_stroke_line(rawfb, x0 - x, y0 - y, x0 + x, y0 - y, 1, col);\n        if (sigma >= 0) {\n            sigma += fb2 * (1 - x);\n            x--;\n        } sigma += a2 * ((4 * y) + 6);\n    }\n}\n\nstatic void\nnk_rawfb_stroke_circle(const struct rawfb_context *rawfb,\n    short x0, short y0, short w, short h, const short line_thickness,\n    const rawfb_color col)\n{\n    /* Bresenham's ellipses */\n    const int a2 = (w * w) / 4;\n    const int b2 = (h * h) / 4;\n    const int fa2 = 4 * a2, fb2 = 4 * b2;\n    int x, y, sigma;\n\n    NK_UNUSED(line_thickness);\n\n    /* Convert upper left to center */\n    h = (h + 1) / 2;\n    w = (w + 1) / 2;\n    x0 += w;\n    y0 += h;\n\n    /* First half */\n    for (x = 0, y = h, sigma = 2*b2+a2*(1-2*h); b2*x <= a2*y; x++) {\n        nk_rawfb_ctx_setpixel(rawfb, x0 + x, y0 + y, col);\n        nk_rawfb_ctx_setpixel(rawfb, x0 - x, y0 + y, col);\n        nk_rawfb_ctx_setpixel(rawfb, x0 + x, y0 - y, col);\n        nk_rawfb_ctx_setpixel(rawfb, x0 - x, y0 - y, col);\n        if (sigma >= 0) {\n            sigma += fa2 * (1 - y);\n            y--;\n        } sigma += b2 * ((4 * x) + 6);\n    }\n    /* Second half */\n    for (x = w, y = 0, sigma = 2*a2+b2*(1-2*w); a2*y <= b2*x; y++) {\n        nk_rawfb_ctx_setpixel(rawfb, x0 + x, y0 + y, col);\n        nk_rawfb_ctx_setpixel(rawfb, x0 - x, y0 + y, col);\n        nk_rawfb_ctx_setpixel(rawfb, x0 + x, y0 - y, col);\n        nk_rawfb_ctx_setpixel(rawfb, x0 - x, y0 - y, col);\n        if (sigma >= 0) {\n            sigma += fb2 * (1 - x);\n            x--;\n        } sigma += a2 * ((4 * y) + 6);\n    }\n}\n\nstatic void\nnk_rawfb_stroke_curve(const struct rawfb_context *rawfb,\n    const struct nk_vec2i p1, const struct nk_vec2i p2,\n    const struct nk_vec2i p3, const struct nk_vec2i p4,\n    const unsigned int num_segments, const unsigned short line_thickness,\n    const rawfb_color col)\n{\n    unsigned int i_step, segments;\n    float t_step;\n    struct nk_vec2i last = p1;\n\n    segments = MAX(num_segments, 1);\n    t_step = 1.0f/(float)segments;\n    for (i_step = 1; i_step <= segments; ++i_step) {\n        float t = t_step * (float)i_step;\n        float u = 1.0f - t;\n        float w1 = u*u*u;\n        float w2 = 3*u*u*t;\n        float w3 = 3*u*t*t;\n        float w4 = t * t *t;\n        float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x;\n        float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y;\n        nk_rawfb_stroke_line(rawfb, last.x, last.y,\n                (short)x, (short)y, line_thickness,col);\n        last.x = (short)x; last.y = (short)y;\n    }\n}\n\nstatic void\nnk_rawfb_clear(const struct rawfb_context *rawfb, const rawfb_color col)\n{\n    nk_rawfb_fill_rect(rawfb, 0, 0, rawfb->fb.w, rawfb->fb.h, 0, col);\n}\n\nNK_API struct rawfb_context*\nnk_rawfb_init(void *fb, void *tex_mem, const unsigned int w, const unsigned int h,\n    const unsigned int pitch, const struct rawfb_pl pl)\n{\n    const void *tex;\n    struct rawfb_context *rawfb;\n\n    rawfb = malloc(sizeof(struct rawfb_context));\n    if (!rawfb)\n        return NULL;\n\n    memset(rawfb, 0, sizeof(struct rawfb_context));\n    rawfb->font_tex.pixels = tex_mem;\n    rawfb->font_tex.pl.bytesPerPixel = 1;\n    rawfb->font_tex.pl.rshift = 0;\n    rawfb->font_tex.pl.gshift = 0;\n    rawfb->font_tex.pl.bshift = 0;\n    rawfb->font_tex.pl.ashift = 0;\n    rawfb->font_tex.pl.rloss = 8;\n    rawfb->font_tex.pl.gloss = 8;\n    rawfb->font_tex.pl.bloss = 8;\n    rawfb->font_tex.pl.aloss = 0;\n    rawfb->font_tex.w = rawfb->font_tex.h = rawfb->font_tex.pitch = 0;\n\n    rawfb->fb.pixels = fb;\n    rawfb->fb.w = w;\n    rawfb->fb.h = h;\n    rawfb->fb.pitch = pitch;\n    rawfb->fb.pl = pl;\n\n    if (0 == nk_init_default(&rawfb->ctx, 0)) {\n        free(rawfb);\n        return NULL;\n    }\n\n    nk_font_atlas_init_default(&rawfb->atlas);\n    nk_font_atlas_begin(&rawfb->atlas);\n    tex = nk_font_atlas_bake(&rawfb->atlas, &rawfb->font_tex.w, &rawfb->font_tex.h, NK_FONT_ATLAS_ALPHA8);\n    if (!tex) {\n        free(rawfb);\n        return NULL;\n    }\n\n    rawfb->font_tex.pitch = rawfb->font_tex.w * 1;\n    memcpy(rawfb->font_tex.pixels, tex, rawfb->font_tex.pitch * rawfb->font_tex.h);\n    nk_font_atlas_end(&rawfb->atlas, nk_handle_ptr(NULL), NULL);\n    if (rawfb->atlas.default_font)\n        nk_style_set_font(&rawfb->ctx, &rawfb->atlas.default_font->handle);\n    nk_style_load_all_cursors(&rawfb->ctx, rawfb->atlas.cursors);\n    nk_rawfb_scissor(rawfb, 0, 0, rawfb->fb.w, rawfb->fb.h);\n\n    return rawfb;\n}\n\nstatic void\nnk_rawfb_stretch_image(const struct rawfb_image *dst,\n    const struct rawfb_image *src, const struct nk_rect *dst_rect,\n    const struct nk_rect *src_rect, const struct nk_rect *dst_scissors,\n    const struct nk_color *fg)\n{\n    short i, j;\n    struct nk_color col;\n    float xinc = src_rect->w / dst_rect->w;\n    float yinc = src_rect->h / dst_rect->h;\n    float xoff = src_rect->x, yoff = src_rect->y;\n\n    /* Simple nearest filtering rescaling */\n    /* TODO: use bilinear filter */\n    for (j = 0; j < (short)dst_rect->h; j++) {\n        for (i = 0; i < (short)dst_rect->w; i++) {\n            if (dst_scissors) {\n                if (i + (int)(dst_rect->x + 0.5f) < dst_scissors->x || i + (int)(dst_rect->x + 0.5f) >= dst_scissors->w)\n                    continue;\n                if (j + (int)(dst_rect->y + 0.5f) < dst_scissors->y || j + (int)(dst_rect->y + 0.5f) >= dst_scissors->h)\n                    continue;\n            }\n            col = nk_rawfb_img_getpixel(src, (int)xoff, (int) yoff);\n            if (col.r || col.g || col.b)\n            {\n                col.r = fg->r;\n                col.g = fg->g;\n                col.b = fg->b;\n            }\n            nk_rawfb_img_blendpixel(dst, i + (int)(dst_rect->x + 0.5f), j + (int)(dst_rect->y + 0.5f), col);\n            xoff += xinc;\n        }\n        xoff = src_rect->x;\n        yoff += yinc;\n    }\n}\n\nstatic void\nnk_rawfb_font_query_font_glyph(nk_handle handle, const float height,\n    struct nk_user_font_glyph *glyph, const nk_rune codepoint,\n    const nk_rune next_codepoint)\n{\n    float scale;\n    const struct nk_font_glyph *g;\n    struct nk_font *font;\n    NK_ASSERT(glyph);\n    NK_UNUSED(next_codepoint);\n\n    font = (struct nk_font*)handle.ptr;\n    NK_ASSERT(font);\n    NK_ASSERT(font->glyphs);\n    if (!font || !glyph)\n        return;\n\n    scale = height/font->info.height;\n    g = nk_font_find_glyph(font, codepoint);\n    glyph->width = (g->x1 - g->x0) * scale;\n    glyph->height = (g->y1 - g->y0) * scale;\n    glyph->offset = nk_vec2(g->x0 * scale, g->y0 * scale);\n    glyph->xadvance = (g->xadvance * scale);\n    glyph->uv[0] = nk_vec2(g->u0, g->v0);\n    glyph->uv[1] = nk_vec2(g->u1, g->v1);\n}\n\nNK_API void\nnk_rawfb_draw_text(const struct rawfb_context *rawfb,\n    const struct nk_user_font *font, const struct nk_rect rect,\n    const char *text, const int len, const float font_height,\n    const struct nk_color fg)\n{\n    float x = 0;\n    int text_len = 0;\n    nk_rune unicode = 0;\n    nk_rune next = 0;\n    int glyph_len = 0;\n    int next_glyph_len = 0;\n    struct nk_user_font_glyph g;\n    if (!len || !text) return;\n\n    x = 0;\n    glyph_len = nk_utf_decode(text, &unicode, len);\n    if (!glyph_len) return;\n\n    /* draw every glyph image */\n    while (text_len < len && glyph_len) {\n        struct nk_rect src_rect;\n        struct nk_rect dst_rect;\n        float char_width = 0;\n        if (unicode == NK_UTF_INVALID) break;\n\n        /* query currently drawn glyph information */\n        next_glyph_len = nk_utf_decode(text + text_len + glyph_len, &next, (int)len - text_len);\n        nk_rawfb_font_query_font_glyph(font->userdata, font_height, &g, unicode,\n                    (next == NK_UTF_INVALID) ? '\\0' : next);\n\n        /* calculate and draw glyph drawing rectangle and image */\n        char_width = g.xadvance;\n        src_rect.x = g.uv[0].x * rawfb->font_tex.w;\n        src_rect.y = g.uv[0].y * rawfb->font_tex.h;\n        src_rect.w = g.uv[1].x * rawfb->font_tex.w - g.uv[0].x * rawfb->font_tex.w;\n        src_rect.h = g.uv[1].y * rawfb->font_tex.h - g.uv[0].y * rawfb->font_tex.h;\n\n        dst_rect.x = x + g.offset.x + rect.x;\n        dst_rect.y = g.offset.y + rect.y;\n        dst_rect.w = ceil(g.width);\n        dst_rect.h = ceil(g.height);\n\n        /* Use software rescaling to blit glyph from font_text to framebuffer */\n        nk_rawfb_stretch_image(&rawfb->fb, &rawfb->font_tex, &dst_rect, &src_rect, &rawfb->scissors, &fg);\n\n        /* offset next glyph */\n        text_len += glyph_len;\n        x += char_width;\n        glyph_len = next_glyph_len;\n        unicode = next;\n    }\n}\n\nNK_API void\nnk_rawfb_drawimage(const struct rawfb_context *rawfb,\n    const int x, const int y, const int w, const int h,\n    const struct nk_image *img, const struct nk_color *col)\n{\n    struct nk_rect src_rect;\n    struct nk_rect dst_rect;\n\n    src_rect.x = img->region[0];\n    src_rect.y = img->region[1];\n    src_rect.w = img->region[2];\n    src_rect.h = img->region[3];\n\n    dst_rect.x = x;\n    dst_rect.y = y;\n    dst_rect.w = w;\n    dst_rect.h = h;\n    nk_rawfb_stretch_image(&rawfb->fb, &rawfb->font_tex, &dst_rect, &src_rect, &rawfb->scissors, col);\n}\n\nNK_API void\nnk_rawfb_shutdown(struct rawfb_context *rawfb)\n{\n    if (rawfb) {\n        nk_free(&rawfb->ctx);\n        memset(rawfb, 0, sizeof(struct rawfb_context));\n        free(rawfb);\n    }\n}\n\nNK_API void\nnk_rawfb_resize_fb(struct rawfb_context *rawfb,\n                   void *fb,\n                   const unsigned int w,\n                   const unsigned int h,\n                   const unsigned int pitch,\n                   const struct rawfb_pl pl)\n{\n    rawfb->fb.w = w;\n    rawfb->fb.h = h;\n    rawfb->fb.pixels = fb;\n    rawfb->fb.pitch = pitch;\n    rawfb->fb.pl = pl;\n}\n\nNK_API void\nnk_rawfb_render(const struct rawfb_context *rawfb,\n                const struct nk_color clear,\n                const unsigned char enable_clear)\n{\n    const struct rawfb_pl *pl = &rawfb->fb.pl;\n    const struct nk_command *cmd;\n\n    if (enable_clear)\n        nk_rawfb_clear(rawfb, nk_rawfb_color2int(clear, pl));\n\n    nk_foreach(cmd, (struct nk_context*)&rawfb->ctx) {\n        switch (cmd->type) {\n        case NK_COMMAND_NOP: break;\n        case NK_COMMAND_SCISSOR: {\n            const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;\n            nk_rawfb_scissor((struct rawfb_context *)rawfb, s->x, s->y, s->w, s->h);\n        } break;\n        case NK_COMMAND_LINE: {\n            const struct nk_command_line *l = (const struct nk_command_line *)cmd;\n            nk_rawfb_stroke_line(rawfb, l->begin.x, l->begin.y, l->end.x,\n                l->end.y, l->line_thickness, nk_rawfb_color2int(l->color, pl));\n        } break;\n        case NK_COMMAND_RECT: {\n            const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;\n            nk_rawfb_stroke_rect(rawfb, r->x, r->y, r->w, r->h,\n                (unsigned short)r->rounding, r->line_thickness,\n                nk_rawfb_color2int(r->color, pl));\n        } break;\n        case NK_COMMAND_RECT_FILLED: {\n            const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;\n            nk_rawfb_fill_rect(rawfb, r->x, r->y, r->w, r->h,\n                (unsigned short)r->rounding, nk_rawfb_color2int(r->color, pl));\n        } break;\n        case NK_COMMAND_CIRCLE: {\n            const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;\n            nk_rawfb_stroke_circle(rawfb, c->x, c->y, c->w, c->h, c->line_thickness,\n                                   nk_rawfb_color2int(c->color, pl));\n        } break;\n        case NK_COMMAND_CIRCLE_FILLED: {\n            const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;\n            nk_rawfb_fill_circle(rawfb, c->x, c->y, c->w, c->h,\n                                 nk_rawfb_color2int(c->color, pl));\n        } break;\n        case NK_COMMAND_TRIANGLE: {\n            const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;\n            nk_rawfb_stroke_triangle(rawfb, t->a.x, t->a.y, t->b.x, t->b.y,\n                t->c.x, t->c.y, t->line_thickness, nk_rawfb_color2int(t->color, pl));\n        } break;\n        case NK_COMMAND_TRIANGLE_FILLED: {\n            const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;\n            nk_rawfb_fill_triangle(rawfb, t->a.x, t->a.y, t->b.x, t->b.y,\n                t->c.x, t->c.y, nk_rawfb_color2int(t->color, pl));\n        } break;\n        case NK_COMMAND_POLYGON: {\n            const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd;\n            nk_rawfb_stroke_polygon(rawfb, p->points, p->point_count, p->line_thickness,\n                                    nk_rawfb_color2int(p->color, pl));\n        } break;\n        case NK_COMMAND_POLYGON_FILLED: {\n            const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;\n            nk_rawfb_fill_polygon(rawfb, p->points, p->point_count, nk_rawfb_color2int(p->color, pl));\n        } break;\n        case NK_COMMAND_POLYLINE: {\n            const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;\n            nk_rawfb_stroke_polyline(rawfb, p->points, p->point_count, p->line_thickness, nk_rawfb_color2int(p->color, pl));\n        } break;\n        case NK_COMMAND_TEXT: {\n            const struct nk_command_text *t = (const struct nk_command_text*)cmd;\n            nk_rawfb_draw_text(rawfb, t->font, nk_rect(t->x, t->y, t->w, t->h),\n                t->string, t->length, t->height, t->foreground);\n        } break;\n        case NK_COMMAND_CURVE: {\n            const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;\n            nk_rawfb_stroke_curve(rawfb, q->begin, q->ctrl[0], q->ctrl[1],\n                q->end, 22, q->line_thickness, nk_rawfb_color2int(q->color, pl));\n        } break;\n        case NK_COMMAND_RECT_MULTI_COLOR: {\n            const struct nk_command_rect_multi_color *q = (const struct nk_command_rect_multi_color *)cmd;\n            nk_rawfb_draw_rect_multi_color(rawfb, q->x, q->y, q->w, q->h, q->left, q->top, q->right, q->bottom);\n        } break;\n        case NK_COMMAND_IMAGE: {\n            const struct nk_command_image *q = (const struct nk_command_image *)cmd;\n            nk_rawfb_drawimage(rawfb, q->x, q->y, q->w, q->h, &q->img, &q->col);\n        } break;\n        case NK_COMMAND_ARC: {\n            assert(0 && \"NK_COMMAND_ARC not implemented\\n\");\n        } break;\n        case NK_COMMAND_ARC_FILLED: {\n            assert(0 && \"NK_COMMAND_ARC_FILLED not implemented\\n\");\n        } break;\n        default: break;\n        }\n    } nk_clear((struct nk_context*)&rawfb->ctx);\n}\n#endif\n\n"
  },
  {
    "path": "demo/rawfb/sdl/Makefile",
    "content": "CFLAGS+=`sdl2-config --cflags --libs`   -std=c89 -Wall -Wextra -pedantic -Wno-unused-function -O0 -g -fvisibility=hidden `pkg-config SDL2_ttf --cflags --libs`\n\n.PHONY: clean\n\ndemo: main.c ../nuklear_rawfb.h\n\t$(CC) -o demo *.c $(CFLAGS) -lrt -lm\n\nclean:\n\t$(RM) demo\n"
  },
  {
    "path": "demo/rawfb/sdl/main.c",
    "content": "#include <SDL.h>\n#include <SDL_mouse.h>\n#include <SDL_keyboard.h>\n\n#ifndef MIN\n#define MIN(a,b) ((a) < (b) ? (a) : (b))\n#endif\n#ifndef MAX\n#define MAX(a,b) ((a) < (b) ? (b) : (a))\n#endif\n\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_IMPLEMENTATION\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_INCLUDE_SOFTWARE_FONT\n#include \"../../../nuklear.h\"\n#define NK_RAWFB_IMPLEMENTATION\n#include \"../nuklear_rawfb.h\"\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../common/node_editor.c\"\n#endif\n\nstatic int translate_sdl_key(struct SDL_Keysym const *k)\n{\n    /*keyboard handling left as an exercise for the reader */\n    NK_UNUSED(k);\n\n    return NK_KEY_NONE;\n}\n\n\nstatic int sdl_button_to_nk(int button)\n{\n    switch(button)\n    {\n        default:\n        /* ft */\n        case SDL_BUTTON_LEFT:\n            return NK_BUTTON_LEFT;\n            break;\n        case SDL_BUTTON_MIDDLE:\n            return NK_BUTTON_MIDDLE;\n            break;\n        case SDL_BUTTON_RIGHT:\n            return NK_BUTTON_RIGHT;\n            break;\n        case SDL_BUTTON_X1:\n            return NK_BUTTON_X1;\n            break;\n        case SDL_BUTTON_X2:\n            return NK_BUTTON_X2;\n            break;\n\n    }\n}\n\n#if 0\nstatic void\ngrid_demo(struct nk_context *ctx)\n{\n    static char text[3][64];\n    static int text_len[3];\n    static const char *items[] = {\"Item 0\",\"item 1\",\"item 2\"};\n    static int selected_item = 0;\n    static int check = 1;\n\n    int i;\n    if (nk_begin(ctx, \"Grid Demo\", nk_rect(600, 350, 275, 250),\n        NK_WINDOW_TITLE|NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|\n        NK_WINDOW_NO_SCROLLBAR))\n    {\n        nk_layout_row_dynamic(ctx, 30, 2);\n        nk_label(ctx, \"Floating point:\", NK_TEXT_RIGHT);\n        nk_edit_string(ctx, NK_EDIT_FIELD, text[0], &text_len[0], 64, nk_filter_float);\n        nk_label(ctx, \"Hexadecimal:\", NK_TEXT_RIGHT);\n        nk_edit_string(ctx, NK_EDIT_FIELD, text[1], &text_len[1], 64, nk_filter_hex);\n        nk_label(ctx, \"Binary:\", NK_TEXT_RIGHT);\n        nk_edit_string(ctx, NK_EDIT_FIELD, text[2], &text_len[2], 64, nk_filter_binary);\n        nk_label(ctx, \"Checkbox:\", NK_TEXT_RIGHT);\n        nk_checkbox_label(ctx, \"Check me\", &check);\n        nk_label(ctx, \"Combobox:\", NK_TEXT_RIGHT);\n        if (nk_combo_begin_label(ctx, items[selected_item], nk_vec2(nk_widget_width(ctx), 200))) {\n            nk_layout_row_dynamic(ctx, 25, 1);\n            for (i = 0; i < 3; ++i)\n                if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))\n                    selected_item = i;\n            nk_combo_end(ctx);\n        }\n    }\n    nk_end(ctx);\n}\n#endif\n\n\nint main(int argc, char **argv)\n{\n    struct nk_color clear = {0,100,0,255};\n    struct nk_vec2 vec;\n    struct nk_rect bounds = {40,40,0,0};\n    struct rawfb_context *context;\n    struct rawfb_pl pl;\n    unsigned char tex_scratch[512 * 512];\n\n    SDL_DisplayMode dm;\n    SDL_Window *window;\n    SDL_Renderer *renderer;\n    SDL_Texture *tex;\n    SDL_Surface *surface;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    NK_UNUSED(argc);\n    NK_UNUSED(argv);\n\n    SDL_Init(SDL_INIT_VIDEO);\n    printf(\"sdl init called...\\n\");\n\n    SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, \"linear\");\n\n    SDL_GetDesktopDisplayMode(0, &dm);\n\n    printf(\"desktop display mode %d %d\\n\", dm.w, dm.h);\n\n\n    window = SDL_CreateWindow(\"Puzzle\", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, dm.w-200,dm.h-200, SDL_WINDOW_OPENGL);\n    if (!window)\n    {\n        printf(\"can't open window!\\n\");\n        exit(1);\n    }\n\n\n    renderer = SDL_CreateRenderer(window, -1, 0);\n\n    surface = SDL_CreateRGBSurfaceWithFormat(0, dm.w-200, dm.h-200, 32, SDL_PIXELFORMAT_ARGB8888);\n\n    pl.bytesPerPixel = surface->format->BytesPerPixel;\n    pl.rshift = surface->format->Rshift;\n    pl.gshift = surface->format->Gshift;\n    pl.bshift = surface->format->Bshift;\n    pl.ashift = surface->format->Ashift;\n    pl.rloss = surface->format->Rloss;\n    pl.gloss = surface->format->Gloss;\n    pl.bloss = surface->format->Bloss;\n    pl.aloss = surface->format->Aloss;\n\n    context = nk_rawfb_init(surface->pixels, tex_scratch, surface->w, surface->h, surface->pitch, pl);\n\n\n    while(1)\n    {\n        SDL_Event event;\n        nk_input_begin(&(context->ctx));\n        while (SDL_PollEvent(&event))\n        {\n            switch(event.type)\n            {\n                case SDL_QUIT:\n                    exit(0);\n                break;\n                case SDL_KEYDOWN:\n                    nk_input_key(&(context->ctx), translate_sdl_key(&event.key.keysym), 1);\n                break;\n                case SDL_KEYUP:\n                    nk_input_key(&(context->ctx), translate_sdl_key(&event.key.keysym), 0);\n                break;\n                case SDL_MOUSEMOTION:\n                    nk_input_motion(&(context->ctx), event.motion.x, event.motion.y);\n                break;\n                case SDL_MOUSEBUTTONDOWN:\n                    nk_input_button(&(context->ctx), sdl_button_to_nk(event.button.button), event.button.x, event.button.y,1);\n                break;\n                case SDL_MOUSEBUTTONUP:\n                    nk_input_button(&(context->ctx), sdl_button_to_nk(event.button.button), event.button.x, event.button.y,0);\n                break;\n                case SDL_MOUSEWHEEL:\n                    vec.x = event.wheel.preciseX;\n                    vec.y = event.wheel.preciseY;\n                    nk_input_scroll(&(context->ctx), vec );\n\n                break;\n            }\n        }\n        nk_input_end(&(context->ctx));\n\n        bounds.w = 400;\n        bounds.h = 400;\n        if (nk_begin(&(context->ctx), \"Test\", bounds, NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE | NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n            nk_layout_row_static(&(context->ctx), 30, 80, 1);\n            if (nk_button_label(&(context->ctx), \"button\")){\n                printf(\"button pressed\\n\");\n            }\n            nk_layout_row_dynamic(&(context->ctx), 40, 2);\n            if (nk_option_label(&(context->ctx), \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(&(context->ctx), \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(&(context->ctx), 45, 1);\n            nk_property_int(&(context->ctx), \"Compression:\", 0, &property, 100, 10, 1);\n        }\n        nk_end(&(context->ctx));\n\n        /* grid_demo(&(context->ctx)); */\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(&(context->ctx));\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(&(context->ctx));\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(&(context->ctx));\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(&(context->ctx), color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(&(context->ctx));\n        #endif\n        /* ----------------------------------------- */\n\n        nk_rawfb_render(context, clear, 1);\n\n\n\n\n        tex = SDL_CreateTextureFromSurface(renderer, surface);\n        SDL_RenderCopy(renderer, tex, NULL, NULL);\n        SDL_RenderPresent(renderer);\n        SDL_DestroyTexture(tex);\n\n    }\n\n    nk_rawfb_shutdown(context);\n\n    SDL_FreeSurface(surface);\n    SDL_DestroyRenderer(renderer);\n    SDL_DestroyWindow(window);\n}\n\n\n"
  },
  {
    "path": "demo/rawfb/wayland/.gitignore",
    "content": "xdg-shell.c\nxdg-shell.h\n"
  },
  {
    "path": "demo/rawfb/wayland/Makefile",
    "content": "WAYLAND=`pkg-config wayland-client --cflags --libs`\nWAYLAND_SCANNER=wayland-scanner\nWAYLAND_PROTOCOLS_DIR=/usr/share/wayland-protocols\n\nCFLAGS+=-std=c99 -Wall -Wextra -pedantic -Wno-unused-function -O3 -fvisibility=hidden\n\n.PHONY: clean\n\ndemo: main.c xdg-shell.c xdg-shell.h\n\t$(CC) $(CFLAGS) -o demo *.c $(WAYLAND) -lrt -lm\n\nxdg-shell.c:\n\t$(WAYLAND_SCANNER) code $(WAYLAND_PROTOCOLS_DIR)/stable/xdg-shell/xdg-shell.xml xdg-shell.c\n\nxdg-shell.h:\n\t$(WAYLAND_SCANNER) client-header $(WAYLAND_PROTOCOLS_DIR)/stable/xdg-shell/xdg-shell.xml xdg-shell.h\n\nclean:\n\t$(RM) demo xdg-shell.c xdg-shell.h\n"
  },
  {
    "path": "demo/rawfb/wayland/main.c",
    "content": "#define _GNU_SOURCE // for O_TMPFILE\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_IMPLEMENTATION\n#define NK_RAWFB_IMPLEMENTATION\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_INCLUDE_SOFTWARE_FONT\n\n#include <wayland-client.h>\n#include <stdlib.h>\n#include <fcntl.h>\n#include <sys/mman.h>\n#include <unistd.h>\n#include <string.h>\n#include <stdio.h>\n#include <math.h>\n#include <time.h>\n#include <sys/time.h>\n\n#include \"../../../nuklear.h\"\n\n#include \"xdg-shell.h\"\n#include \"../nuklear_rawfb.h\"\n\nstruct nk_wayland {\n    /*wayland vars*/\n    struct wl_display *display;\n    struct wl_compositor *compositor;\n    struct xdg_wm_base *xdg_wm_base;\n    struct wl_shm *wl_shm;\n    struct wl_seat* seat;\n    struct wl_callback *frame_callback;\n    struct wl_surface *surface;\n    struct xdg_surface *xdg_surface;\n    struct xdg_toplevel *xdg_toplevel;\n    struct wl_buffer *front_buffer;\n\n    int32_t *data;\n    int mouse_pointer_x;\n    int mouse_pointer_y;\n    uint8_t tex_scratch[512 * 512];\n\n    struct rawfb_context *rawfb;\n};\n\n#define WIDTH 800\n#define HEIGHT 600\n\n#define DTIME           20\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../common/node_editor.c\"\n#endif\n\n\n//WAYLAND OUTPUT INTERFACE\nstatic void nk_wayland_output_cb_geometry(void *data, struct wl_output *wl_output, int x, int y, int w, int h, int subpixel, const char *make, const char *model, int transform)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(wl_output);\n    NK_UNUSED(subpixel);\n    NK_UNUSED(make);\n    NK_UNUSED(model);\n    NK_UNUSED(transform);\n\n    printf(\"wl_output geometry x=%d, y=%d, w=%d, h=%d make=%s, model=%s \\n\", x,y,w,h, make, model);\n}\n\nstatic void nk_wayland_output_cb_mode(void *data, struct wl_output *wl_output, unsigned int flags, int w, int h, int refresh)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(wl_output);\n    NK_UNUSED(flags);\n    NK_UNUSED(w);\n    NK_UNUSED(h);\n    NK_UNUSED(refresh);\n}\n\nstatic void nk_wayland_output_cb_done(void *data, struct wl_output *output)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(output);\n}\n\nstatic void nk_wayland_output_cb_scale(void *data, struct wl_output *output, int scale)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(output);\n    NK_UNUSED(scale);\n}\n\nstatic const struct wl_output_listener nk_wayland_output_listener =\n{\n   &nk_wayland_output_cb_geometry,\n   &nk_wayland_output_cb_mode,\n   &nk_wayland_output_cb_done,\n   &nk_wayland_output_cb_scale\n};\n//-------------------------------------------------------------------- endof WAYLAND OUTPUT INTERFACE\n\n//WAYLAND POINTER INTERFACE (mouse/touchpad)\nstatic void nk_wayland_pointer_enter (void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(pointer);\n    NK_UNUSED(serial);\n    NK_UNUSED(surface);\n    NK_UNUSED(surface_x);\n    NK_UNUSED(surface_y);\n}\n\nstatic void nk_wayland_pointer_leave (void *data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(pointer);\n    NK_UNUSED(serial);\n    NK_UNUSED(surface);\n}\n\nstatic void nk_wayland_pointer_motion (void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t x, wl_fixed_t y)\n{\n    struct nk_wayland* win = (struct nk_wayland*)data;\n\n    NK_UNUSED(pointer);\n    NK_UNUSED(time);\n\n    win->mouse_pointer_x = wl_fixed_to_int(x);\n    win->mouse_pointer_y = wl_fixed_to_int(y);\n\n    nk_input_motion(&(win->rawfb->ctx), win->mouse_pointer_x, win->mouse_pointer_y);\n}\n\nstatic void nk_wayland_pointer_button (void *data, struct wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)\n{\n    struct nk_wayland* win = (struct nk_wayland*)data;\n\n    NK_UNUSED(pointer);\n    NK_UNUSED(serial);\n    NK_UNUSED(time);\n\n    switch (button) {\n    case 272: // Left Mouse Button\n        if (state == WL_POINTER_BUTTON_STATE_PRESSED) {\n            nk_input_button(&(win->rawfb->ctx), NK_BUTTON_LEFT, win->mouse_pointer_x, win->mouse_pointer_y, 1);\n        } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {\n            nk_input_button(&(win->rawfb->ctx), NK_BUTTON_LEFT, win->mouse_pointer_x, win->mouse_pointer_y, 0);\n        }\n        break;\n    case 273: // Right Mouse Button\n        if (state == WL_POINTER_BUTTON_STATE_PRESSED) {\n            nk_input_button(&(win->rawfb->ctx), NK_BUTTON_RIGHT, win->mouse_pointer_x, win->mouse_pointer_y, 1);\n        } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {\n            nk_input_button(&(win->rawfb->ctx), NK_BUTTON_RIGHT, win->mouse_pointer_x, win->mouse_pointer_y, 0);\n        }\n        break;\n    case 274: // Middle Mouse Button\n        if (state == WL_POINTER_BUTTON_STATE_PRESSED) {\n            nk_input_button(&(win->rawfb->ctx), NK_BUTTON_MIDDLE, win->mouse_pointer_x, win->mouse_pointer_y, 1);\n        } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {\n            nk_input_button(&(win->rawfb->ctx), NK_BUTTON_MIDDLE, win->mouse_pointer_x, win->mouse_pointer_y, 0);\n        }\n        break;\n    case 275: // X1\n        if (state == WL_POINTER_BUTTON_STATE_PRESSED) {\n            nk_input_button(&(win->rawfb->ctx), NK_BUTTON_X1, win->mouse_pointer_x, win->mouse_pointer_y, 1);\n        } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {\n            nk_input_button(&(win->rawfb->ctx), NK_BUTTON_X1, win->mouse_pointer_x, win->mouse_pointer_y, 0);\n        }\n        break;\n    case 276: // X2\n        if (state == WL_POINTER_BUTTON_STATE_PRESSED) {\n            nk_input_button(&(win->rawfb->ctx), NK_BUTTON_X2, win->mouse_pointer_x, win->mouse_pointer_y, 1);\n        } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {\n            nk_input_button(&(win->rawfb->ctx), NK_BUTTON_X2, win->mouse_pointer_x, win->mouse_pointer_y, 0);\n        }\n        break;\n    }\n}\n\nstatic void nk_wayland_pointer_axis (void *data, struct wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(pointer);\n    NK_UNUSED(time);\n    NK_UNUSED(axis);\n    NK_UNUSED(value);\n}\n\nstatic struct wl_pointer_listener nk_wayland_pointer_listener =\n{\n    &nk_wayland_pointer_enter,\n    &nk_wayland_pointer_leave,\n    &nk_wayland_pointer_motion,\n    &nk_wayland_pointer_button,\n    &nk_wayland_pointer_axis,\n    NULL,\n    NULL,\n    NULL,\n    NULL\n};\n//-------------------------------------------------------------------- endof WAYLAND POINTER INTERFACE\n\n//WAYLAND KEYBOARD INTERFACE\nstatic void nk_wayland_keyboard_keymap (void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(keyboard);\n    NK_UNUSED(format);\n    NK_UNUSED(fd);\n    NK_UNUSED(size);\n}\n\nstatic void nk_wayland_keyboard_enter (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(keyboard);\n    NK_UNUSED(serial);\n    NK_UNUSED(surface);\n    NK_UNUSED(keys);\n}\n\nstatic void nk_wayland_keyboard_leave (void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(keyboard);\n    NK_UNUSED(serial);\n    NK_UNUSED(surface);\n}\n\nstatic void nk_wayland_keyboard_key (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(keyboard);\n    NK_UNUSED(serial);\n    NK_UNUSED(time);\n    NK_UNUSED(state);\n    printf(\"key: %d \\n\", key);\n}\n\nstatic void nk_wayland_keyboard_modifiers (void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(keyboard);\n    NK_UNUSED(serial);\n    NK_UNUSED(mods_depressed);\n    NK_UNUSED(mods_latched);\n    NK_UNUSED(mods_locked);\n    NK_UNUSED(group);\n}\n\nstatic struct wl_keyboard_listener nk_wayland_keyboard_listener =\n{\n    &nk_wayland_keyboard_keymap,\n    &nk_wayland_keyboard_enter,\n    &nk_wayland_keyboard_leave,\n    &nk_wayland_keyboard_key,\n    &nk_wayland_keyboard_modifiers,\n    NULL\n};\n//-------------------------------------------------------------------- endof WAYLAND KEYBOARD INTERFACE\n\n//WAYLAND SEAT INTERFACE\nstatic void seat_capabilities (void *data, struct wl_seat *seat, uint32_t capabilities)\n{\n     struct nk_wayland* win = (struct nk_wayland*)data;\n\n\tif (capabilities & WL_SEAT_CAPABILITY_POINTER) {\n\t\tstruct wl_pointer *pointer = wl_seat_get_pointer (seat);\n\t\twl_pointer_add_listener (pointer, &nk_wayland_pointer_listener, win);\n\t}\n\tif (capabilities & WL_SEAT_CAPABILITY_KEYBOARD) {\n\t\tstruct wl_keyboard *keyboard = wl_seat_get_keyboard (seat);\n\t\twl_keyboard_add_listener (keyboard, &nk_wayland_keyboard_listener, win);\n\t}\n}\n\nstatic struct wl_seat_listener seat_listener =\n{\n    &seat_capabilities,\n    NULL\n};\n//-------------------------------------------------------------------- endof WAYLAND SEAT INTERFACE\n\n// WAYLAND SHELL INTERFACE\nstatic void nk_wayland_xdg_wm_base_ping (void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)\n{\n    NK_UNUSED(data);\n    xdg_wm_base_pong (xdg_wm_base, serial);\n}\n\nstatic struct xdg_wm_base_listener nk_wayland_xdg_wm_base_listener =\n{\n    &nk_wayland_xdg_wm_base_ping\n};\n\nstatic void nk_wayland_xdg_surface_configure (void *data, struct xdg_surface *xdg_surface, uint32_t serial)\n{\n    NK_UNUSED(data);\n    xdg_surface_ack_configure(xdg_surface, serial);\n}\n\nstatic struct xdg_surface_listener nk_wayland_xdg_surface_listener =\n{\n    &nk_wayland_xdg_surface_configure,\n};\n\nstatic void nk_wayland_xdg_toplevel_configure (void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *states)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(xdg_toplevel);\n    NK_UNUSED(width);\n    NK_UNUSED(height);\n    NK_UNUSED(states);\n}\n\nstatic void nk_wayland_xdg_toplevel_close (void *data, struct xdg_toplevel *xdg_toplevel)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(xdg_toplevel);\n}\n\nstatic struct xdg_toplevel_listener nk_wayland_xdg_toplevel_listener =\n{\n    &nk_wayland_xdg_toplevel_configure,\n    &nk_wayland_xdg_toplevel_close\n};\n//--------------------------------------------------------------------- endof WAYLAND SHELL INTERFACE\n\n\n// WAYLAND REGISTRY INTERFACE\nstatic void nk_wayland_registry_add_object (void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version)\n{\n    struct nk_wayland* win = (struct nk_wayland*)data;\n\n    NK_UNUSED(version);\n\n    //printf(\"looking for %s interface \\n\", interface);\n\tif (!strcmp(interface,\"wl_compositor\")) {\n\t\twin->compositor = wl_registry_bind (registry, name, &wl_compositor_interface, 1);\n\n\t} else if (!strcmp(interface,\"xdg_wm_base\")) {\n\t\twin->xdg_wm_base = wl_registry_bind (registry, name, &xdg_wm_base_interface, 1);\n\t\txdg_wm_base_add_listener (win->xdg_wm_base, &nk_wayland_xdg_wm_base_listener, win);\n\t} else if (!strcmp(interface,\"wl_shm\")) {\n\t\twin->wl_shm = wl_registry_bind (registry, name, &wl_shm_interface, 1);\n\n\t} else if (!strcmp(interface,\"wl_seat\")) {\n\t\twin->seat = wl_registry_bind (registry, name, &wl_seat_interface, 1);\n\t\twl_seat_add_listener (win->seat, &seat_listener, win);\n\n\t} else if (!strcmp(interface, \"wl_output\")) {\n        struct wl_output *wl_output = wl_registry_bind(registry, name, &wl_output_interface, 1);\n        wl_output_add_listener(wl_output, &nk_wayland_output_listener, NULL);\n    }\n}\n\nstatic void nk_wayland_registry_remove_object (void *data, struct wl_registry *registry, uint32_t name)\n{\n    NK_UNUSED(data);\n    NK_UNUSED(registry);\n    NK_UNUSED(name);\n}\n\nstatic struct wl_registry_listener nk_wayland_registry_listener =\n{\n    &nk_wayland_registry_add_object,\n    &nk_wayland_registry_remove_object\n};\n//------------------------------------------------------------------------------------------------ endof WAYLAND REGISTRY INTERFACE\n\nstatic void nk_wayland_deinit(struct nk_wayland *win)\n{\n\txdg_toplevel_destroy (win->xdg_toplevel);\n\txdg_surface_destroy (win->xdg_surface);\n\txdg_wm_base_destroy (win->xdg_wm_base);\n\twl_surface_destroy (win->surface);\n}\n\nstatic long timestamp(void)\n{\n    struct timeval tv;\n    if (gettimeofday(&tv, NULL) < 0) return 0;\n    return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);\n}\n\nstatic void sleep_for(long t)\n{\n    struct timespec req;\n    const time_t sec = (int)(t/1000);\n    const long ms = t - (sec * 1000);\n    req.tv_sec = sec;\n    req.tv_nsec = ms * 1000000L;\n    while(-1 == nanosleep(&req, &req));\n}\n\nstatic void nk_wayland_surf_clear(struct nk_wayland* win)\n{\n    int x, y;\n    int pix_idx;\n\n    for (y = 0; y < HEIGHT; y++){\n        for (x = 0; x < WIDTH; x++){\n            pix_idx = y * WIDTH + x;\n            win->data[pix_idx] = 0xFF000000;\n        }\n    }\n}\n\n//This causes the screen to refresh\nstatic const struct wl_callback_listener frame_listener;\n\nstatic void redraw(void *data, struct wl_callback *callback, uint32_t time)\n{\n  //  printf(\"redrawing.. 1\\n\");\n    struct nk_wayland* win = (struct nk_wayland*)data;\n\n    NK_UNUSED(callback);\n    NK_UNUSED(time);\n\n    wl_callback_destroy(win->frame_callback);\n    wl_surface_damage(win->surface, 0, 0, WIDTH, HEIGHT);\n\n\n\n    win->frame_callback = wl_surface_frame(win->surface);\n    wl_surface_attach(win->surface, win->front_buffer, 0, 0);\n    wl_callback_add_listener(win->frame_callback, &frame_listener, win);\n    wl_surface_commit(win->surface);\n\n}\n\n\nstatic const struct wl_callback_listener frame_listener = {\n    redraw\n};\n\nint main ()\n{\n    long dt;\n    long started;\n    struct nk_wayland nk_wayland_ctx;\n    struct wl_registry *registry;\n    int running = 1;\n    struct rawfb_pl pl;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    //1. Initialize display\n\tnk_wayland_ctx.display = wl_display_connect (NULL);\n    if (nk_wayland_ctx.display == NULL) {\n        printf(\"no wayland display found. do you have wayland composer running? \\n\");\n        return -1;\n    }\n\n\tregistry = wl_display_get_registry (nk_wayland_ctx.display);\n\twl_registry_add_listener (registry, &nk_wayland_registry_listener, &nk_wayland_ctx);\n\twl_display_roundtrip (nk_wayland_ctx.display);\n\n\n    //2. Create Window\n\tnk_wayland_ctx.surface = wl_compositor_create_surface (nk_wayland_ctx.compositor);\n\n\tnk_wayland_ctx.xdg_surface = xdg_wm_base_get_xdg_surface(nk_wayland_ctx.xdg_wm_base, nk_wayland_ctx.surface);\n\txdg_surface_add_listener (nk_wayland_ctx.xdg_surface, &nk_wayland_xdg_surface_listener, &nk_wayland_ctx);\n\n\tnk_wayland_ctx.xdg_toplevel = xdg_surface_get_toplevel(nk_wayland_ctx.xdg_surface);\n\txdg_toplevel_add_listener (nk_wayland_ctx.xdg_toplevel, &nk_wayland_xdg_toplevel_listener, &nk_wayland_ctx);\n\n    nk_wayland_ctx.frame_callback = wl_surface_frame(nk_wayland_ctx.surface);\n    wl_callback_add_listener(nk_wayland_ctx.frame_callback, &frame_listener, &nk_wayland_ctx);\n\n    wl_surface_commit (nk_wayland_ctx.surface);\n\n\tsize_t size = WIDTH * HEIGHT * 4;\n\tchar *xdg_runtime_dir = getenv (\"XDG_RUNTIME_DIR\");\n\tint fd = open (xdg_runtime_dir, O_TMPFILE|O_RDWR|O_EXCL, 0600);\n\tftruncate (fd, size);\n\tnk_wayland_ctx.data = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);\n\tstruct wl_shm_pool *pool = wl_shm_create_pool (nk_wayland_ctx.wl_shm, fd, size);\n\tnk_wayland_ctx.front_buffer = wl_shm_pool_create_buffer (pool, 0, WIDTH, HEIGHT, WIDTH*4, WL_SHM_FORMAT_XRGB8888);\n\twl_shm_pool_destroy (pool);\n\tclose (fd);\n\n\twl_display_roundtrip (nk_wayland_ctx.display);\n\n\n    //3. Clear window and start rendering loop\n\tnk_wayland_surf_clear(&nk_wayland_ctx);\n    wl_surface_attach (nk_wayland_ctx.surface, nk_wayland_ctx.front_buffer, 0, 0);\n    wl_surface_commit (nk_wayland_ctx.surface);\n\n    pl.bytesPerPixel = 4;\n    pl.ashift = 24;\n    pl.rshift = 16;\n    pl.gshift = 8;\n    pl.bshift = 0;\n    pl.aloss = 0;\n    pl.rloss = 0;\n    pl.gloss = 0;\n    pl.bloss = 0;\n\n    nk_wayland_ctx.rawfb = nk_rawfb_init(nk_wayland_ctx.data, nk_wayland_ctx.tex_scratch, WIDTH, HEIGHT, WIDTH*4, pl);\n\n\n    //4. rendering UI\n    while (running) {\n        started = timestamp();\n\n        // GUI\n        if (nk_begin(&(nk_wayland_ctx.rawfb->ctx), \"Demo\", nk_rect(50, 50, 200, 200),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|\n            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(&(nk_wayland_ctx.rawfb->ctx), 30, 80, 1);\n            if (nk_button_label(&(nk_wayland_ctx.rawfb->ctx), \"button\")){\n                printf(\"button pressed\\n\");\n            }\n            nk_layout_row_dynamic(&(nk_wayland_ctx.rawfb->ctx), 30, 2);\n            if (nk_option_label(&(nk_wayland_ctx.rawfb->ctx), \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(&(nk_wayland_ctx.rawfb->ctx), \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(&(nk_wayland_ctx.rawfb->ctx), 25, 1);\n            nk_property_int(&(nk_wayland_ctx.rawfb->ctx), \"Compression:\", 0, &property, 100, 10, 1);\n        }\n        nk_end(&(nk_wayland_ctx.rawfb->ctx));\n\n        if (nk_window_is_closed(&(nk_wayland_ctx.rawfb->ctx), \"Demo\")) break;\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(&(nk_wayland_ctx.rawfb->ctx));\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(&(nk_wayland_ctx.rawfb->ctx));\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(&(nk_wayland_ctx.rawfb->ctx));\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(&(nk_wayland_ctx.rawfb->ctx), color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(&(nk_wayland_ctx.rawfb->ctx));\n        #endif\n        /* ----------------------------------------- */\n\n        // Draw framebuffer\n        nk_rawfb_render(nk_wayland_ctx.rawfb, nk_rgb(30,30,30), 1);\n\n\n        //handle wayland stuff (send display to FB & get inputs)\n        nk_input_begin(&(nk_wayland_ctx.rawfb->ctx));\n        wl_display_dispatch(nk_wayland_ctx.display);\n        nk_input_end(&(nk_wayland_ctx.rawfb->ctx));\n\n        // Timing\n        dt = timestamp() - started;\n        if (dt < DTIME)\n            sleep_for(DTIME - dt);\n    }\n\n\tnk_wayland_deinit (&nk_wayland_ctx);\n\twl_display_disconnect (nk_wayland_ctx.display);\n\treturn 0;\n}\n"
  },
  {
    "path": "demo/rawfb/x11/Makefile",
    "content": "# Install\nBIN = demo\n\n# Flags\nCFLAGS += -std=c89 -Wall -Wextra -pedantic -Wno-unused-function\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\n$(BIN):\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -D_GNU_SOURCE -D_POSIX_C_SOURCE=200809L -o bin/$(BIN) -lX11 -lXext -lm\n"
  },
  {
    "path": "demo/rawfb/x11/main.c",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2016-2017 Patrick Rudolph <siro@das-labor.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n *\n * Based on x11/main.c.\n *\n*/\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#include <string.h>\n#include <limits.h>\n#include <math.h>\n#include <sys/time.h>\n#include <unistd.h>\n#include <time.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_IMPLEMENTATION\n#define NK_XLIBSHM_IMPLEMENTATION\n#define NK_RAWFB_IMPLEMENTATION\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_INCLUDE_SOFTWARE_FONT\n\n#include \"../../../nuklear.h\"\n#include \"../nuklear_rawfb.h\"\n#include \"nuklear_xlib.h\"\n\n#define DTIME           20\n#define WINDOW_WIDTH    800\n#define WINDOW_HEIGHT   600\n\n#define UNUSED(a) (void)a\n#define MIN(a,b) ((a) < (b) ? (a) : (b))\n#define MAX(a,b) ((a) < (b) ? (b) : (a))\n#define LEN(a) (sizeof(a)/sizeof(a)[0])\n\ntypedef struct XWindow XWindow;\nstruct XWindow {\n    Display *dpy;\n    Window root;\n    Visual *vis;\n    Colormap cmap;\n    XWindowAttributes attr;\n    XSetWindowAttributes swa;\n    Window win;\n    int screen;\n    unsigned int width;\n    unsigned int height;\n};\n\nstatic void\ndie(const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    fputs(\"\\n\", stderr);\n    exit(EXIT_FAILURE);\n}\n\nstatic long\ntimestamp(void)\n{\n    struct timeval tv;\n    if (gettimeofday(&tv, NULL) < 0) return 0;\n    return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);\n}\n\nstatic void\nsleep_for(long t)\n{\n    struct timespec req;\n    const time_t sec = (int)(t/1000);\n    const long ms = t - (sec * 1000);\n    req.tv_sec = sec;\n    req.tv_nsec = ms * 1000000L;\n    while(-1 == nanosleep(&req, &req));\n}\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nint\nmain(void)\n{\n    long dt;\n    long started;\n    int running = 1;\n    int status;\n    XWindow xw;\n    struct rawfb_context *rawfb;\n    void *fb = NULL;\n    struct rawfb_pl pl;\n    unsigned char tex_scratch[512 * 512];\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    /* X11 */\n    memset(&xw, 0, sizeof xw);\n    xw.dpy = XOpenDisplay(NULL);\n    if (!xw.dpy) die(\"Could not open a display; perhaps $DISPLAY is not set?\");\n\n    xw.root = DefaultRootWindow(xw.dpy);\n    xw.screen = XDefaultScreen(xw.dpy);\n    xw.vis = XDefaultVisual(xw.dpy, xw.screen);\n    xw.cmap = XCreateColormap(xw.dpy,xw.root,xw.vis,AllocNone);\n    xw.swa.colormap = xw.cmap;\n    xw.swa.event_mask =\n        ExposureMask | KeyPressMask | KeyReleaseMask |\n        ButtonPress | ButtonReleaseMask| ButtonMotionMask |\n        Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|\n        PointerMotionMask | KeymapStateMask | EnterWindowMask | LeaveWindowMask;\n    xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0,\n        XDefaultDepth(xw.dpy, xw.screen), InputOutput,\n        xw.vis, CWEventMask | CWColormap, &xw.swa);\n\n    XStoreName(xw.dpy, xw.win, \"X11\");\n    XMapWindow(xw.dpy, xw.win);\n    XGetWindowAttributes(xw.dpy, xw.win, &xw.attr);\n    xw.width = (unsigned int)xw.attr.width;\n    xw.height = (unsigned int)xw.attr.height;\n\n    /* Framebuffer emulator */\n    status = nk_xlib_init(xw.dpy, xw.vis, xw.screen, xw.win, xw.width, xw.height, &fb, &pl);\n    if (!status || !fb)\n        return 0;\n\n    /* GUI */\n    rawfb = nk_rawfb_init(fb, tex_scratch, xw.width, xw.height, xw.width * 4, pl);\n    if (!rawfb) running = 0;\n\n    while (running) {\n        /* Input */\n        XEvent evt;\n        started = timestamp();\n        nk_input_begin(&rawfb->ctx);\n        while (XCheckWindowEvent(xw.dpy, xw.win, xw.swa.event_mask, &evt)) {\n            if (XFilterEvent(&evt, xw.win)) continue;\n            nk_xlib_handle_event(xw.dpy, xw.screen, xw.win, &evt, rawfb);\n        }\n        nk_input_end(&rawfb->ctx);\n\n        /* GUI */\n        if (nk_begin(&rawfb->ctx, \"Demo\", nk_rect(50, 50, 200, 200),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|\n            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE)) {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(&rawfb->ctx, 30, 80, 1);\n            if (nk_button_label(&rawfb->ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(&rawfb->ctx, 30, 2);\n            if (nk_option_label(&rawfb->ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(&rawfb->ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(&rawfb->ctx, 25, 1);\n            nk_property_int(&rawfb->ctx, \"Compression:\", 0, &property, 100, 10, 1);\n        }\n        nk_end(&rawfb->ctx);\n        if (nk_window_is_closed(&rawfb->ctx, \"Demo\")) break;\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(&rawfb->ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(&rawfb->ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(&rawfb->ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(&rawfb->ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(&rawfb->ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw framebuffer */\n        nk_rawfb_render(rawfb, nk_rgb(30,30,30), 1);\n\n        /* Emulate framebuffer */\n        XClearWindow(xw.dpy, xw.win);\n        nk_xlib_render(xw.win);\n        XFlush(xw.dpy);\n\n        /* Timing */\n        dt = timestamp() - started;\n        if (dt < DTIME)\n            sleep_for(DTIME - dt);\n    }\n\n    nk_rawfb_shutdown(rawfb);\n    nk_xlib_shutdown();\n    XUnmapWindow(xw.dpy, xw.win);\n    XFreeColormap(xw.dpy, xw.cmap);\n    XDestroyWindow(xw.dpy, xw.win);\n    XCloseDisplay(xw.dpy);\n    return 0;\n}\n\n"
  },
  {
    "path": "demo/rawfb/x11/nuklear_xlib.h",
    "content": "/*\n * MIT License\n *\n * Copyright (c) 2016-2017 Patrick Rudolph <siro@das-labor.org>\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to deal\n * in the Software without restriction, including without limitation the rights\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n * copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n\n * The above copyright notice and this permission notice shall be included in all\n * copies or substantial portions of the Software.\n\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n * SOFTWARE.\n *\n * Based on x11/nuklear_xlib.h.\n*/\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_XLIBSHM_H_\n#define NK_XLIBSHM_H_\n\n#include <X11/Xlib.h>\n\nNK_API int  nk_xlib_init(Display *dpy, Visual *vis, int screen, Window root, unsigned int w, unsigned int h, void **fb, struct rawfb_pl *pl);\nNK_API int  nk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt, struct rawfb_context *rawfb);\nNK_API void nk_xlib_render(Drawable screen);\nNK_API void nk_xlib_shutdown(void);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_XLIBSHM_IMPLEMENTATION\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <X11/Xlib.h>\n#include <X11/Xutil.h>\n#include <X11/Xresource.h>\n#include <X11/Xlocale.h>\n#include <X11/extensions/XShm.h>\n#include <sys/ipc.h>\n#include <sys/shm.h>\n\nstatic struct  {\n    struct nk_context ctx;\n    struct XSurface *surf;\n    Cursor cursor;\n    Display *dpy;\n    Window root;\n    XImage *ximg;\n    XShmSegmentInfo xsi;\n    char fallback;\n    GC gc;\n} xlib;\n\nNK_API int\nnk_xlib_init(Display *dpy, Visual *vis, int screen, Window root,\n    unsigned int w, unsigned int h, void **fb, struct rawfb_pl *pl)\n{\n    unsigned int depth = XDefaultDepth(dpy, screen);\n    xlib.dpy = dpy;\n    xlib.root = root;\n\n    if (!setlocale(LC_ALL,\"\")) return 0;\n    if (!XSupportsLocale()) return 0;\n    if (!XSetLocaleModifiers(\"@im=none\")) return 0;\n\n    /* create invisible cursor */\n    {static XColor dummy; char data[1] = {0};\n    Pixmap blank = XCreateBitmapFromData(dpy, root, data, 1, 1);\n    if (blank == None) return 0;\n    xlib.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);\n    XFreePixmap(dpy, blank);}\n\n    xlib.fallback = False;\n    do {/* Initialize shared memory according to:\n         * https://www.x.org/archive/X11R7.5/doc/Xext/mit-shm.html */\n        int status;\n        if (!XShmQueryExtension(dpy)) {\n            printf(\"No XShm Extension available.\\n\");\n            xlib.fallback = True;\n            break;\n        }\n        xlib.ximg = XShmCreateImage(dpy, vis, depth, ZPixmap, NULL, &xlib.xsi, w, h);\n        if (!xlib.ximg) {\n            xlib.fallback = True;\n            break;\n        }\n        xlib.xsi.shmid = shmget(IPC_PRIVATE, xlib.ximg->bytes_per_line * xlib.ximg->height, IPC_CREAT | 0777);\n        if (xlib.xsi.shmid < 0) {\n            XDestroyImage(xlib.ximg);\n            xlib.fallback = True;\n            break;\n        }\n        xlib.xsi.shmaddr = xlib.ximg->data = shmat(xlib.xsi.shmid, NULL, 0);\n        if ((intptr_t)xlib.xsi.shmaddr < 0) {\n            XDestroyImage(xlib.ximg);\n            xlib.fallback = True;\n            break;\n        }\n        xlib.xsi.readOnly = False;\n        status = XShmAttach(dpy, &xlib.xsi);\n        if (!status) {\n            shmdt(xlib.xsi.shmaddr);\n            XDestroyImage(xlib.ximg);\n            xlib.fallback = True;\n            break;\n        } XSync(dpy, False);\n        shmctl(xlib.xsi.shmid, IPC_RMID, NULL);\n    } while(0);\n\n    if (xlib.fallback) {\n        xlib.ximg = XCreateImage(dpy, vis, depth, ZPixmap, 0, NULL, w, h, 32, 0);\n        if (!xlib.ximg) return 0;\n        xlib.ximg->data = malloc(h * xlib.ximg->bytes_per_line);\n        if (!xlib.ximg->data)\n            return 0;\n    }\n    xlib.gc = XDefaultGC(dpy, screen);\n    *fb = xlib.ximg->data;\n\n    pl->bytesPerPixel = xlib.ximg->bits_per_pixel / 8;\n    pl->rshift = __builtin_ctzl(xlib.ximg->red_mask);\n    pl->gshift = __builtin_ctzl(xlib.ximg->green_mask);\n    pl->bshift = __builtin_ctzl(xlib.ximg->blue_mask);\n    pl->ashift = 0;\n    pl->rloss = 8 - __builtin_popcount(xlib.ximg->red_mask);\n    pl->gloss = 8 - __builtin_popcount(xlib.ximg->green_mask);\n    pl->bloss = 8 - __builtin_popcount(xlib.ximg->blue_mask);\n    pl->aloss = 8;\n\n    return 1;\n}\n\nNK_API int\nnk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt, struct rawfb_context *rawfb)\n{\n    /* optional grabbing behavior */\n    if (rawfb->ctx.input.mouse.grab) {\n        /* XDefineCursor(xlib.dpy, xlib.root, xlib.cursor); */\n        rawfb->ctx.input.mouse.grab = 0;\n    } else if (rawfb->ctx.input.mouse.ungrab) {\n        XWarpPointer(xlib.dpy, None, xlib.root, 0, 0, 0, 0,\n            (int)rawfb->ctx.input.mouse.prev.x, (int)rawfb->ctx.input.mouse.prev.y);\n        /* XUndefineCursor(xlib.dpy, xlib.root); */\n        rawfb->ctx.input.mouse.ungrab = 0;\n    }\n\n    if (evt->type == KeyPress || evt->type == KeyRelease)\n    {\n        /* Key handler */\n        int ret, down = (evt->type == KeyPress);\n        KeySym *code = XGetKeyboardMapping(xlib.dpy, (KeyCode)evt->xkey.keycode, 1, &ret);\n        if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(&rawfb->ctx, NK_KEY_SHIFT, down);\n        else if (*code == XK_Control_L || *code == XK_Control_R) nk_input_key(&rawfb->ctx, NK_KEY_CTRL, down);\n        else if (*code == XK_Delete)    nk_input_key(&rawfb->ctx, NK_KEY_DEL, down);\n        else if (*code == XK_Return)    nk_input_key(&rawfb->ctx, NK_KEY_ENTER, down);\n        else if (*code == XK_Tab)       nk_input_key(&rawfb->ctx, NK_KEY_TAB, down);\n        else if (*code == XK_Left)      nk_input_key(&rawfb->ctx, NK_KEY_LEFT, down);\n        else if (*code == XK_Right)     nk_input_key(&rawfb->ctx, NK_KEY_RIGHT, down);\n        else if (*code == XK_Up)        nk_input_key(&rawfb->ctx, NK_KEY_UP, down);\n        else if (*code == XK_Down)      nk_input_key(&rawfb->ctx, NK_KEY_DOWN, down);\n        else if (*code == XK_BackSpace) nk_input_key(&rawfb->ctx, NK_KEY_BACKSPACE, down);\n        else if (*code == XK_Escape)    nk_input_key(&rawfb->ctx, NK_KEY_TEXT_RESET_MODE, down);\n        else if (*code == XK_Page_Up)   nk_input_key(&rawfb->ctx, NK_KEY_SCROLL_UP, down);\n        else if (*code == XK_Page_Down) nk_input_key(&rawfb->ctx, NK_KEY_SCROLL_DOWN, down);\n        else if (*code == XK_Home) {\n            nk_input_key(&rawfb->ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(&rawfb->ctx, NK_KEY_SCROLL_START, down);\n        } else if (*code == XK_End) {\n            nk_input_key(&rawfb->ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(&rawfb->ctx, NK_KEY_SCROLL_END, down);\n        } else {\n            if (*code == 'c' && (evt->xkey.state & ControlMask))\n                nk_input_key(&rawfb->ctx, NK_KEY_COPY, down);\n            else if (*code == 'v' && (evt->xkey.state & ControlMask))\n                nk_input_key(&rawfb->ctx, NK_KEY_PASTE, down);\n            else if (*code == 'x' && (evt->xkey.state & ControlMask))\n                nk_input_key(&rawfb->ctx, NK_KEY_CUT, down);\n            else if (*code == 'z' && (evt->xkey.state & ControlMask))\n                nk_input_key(&rawfb->ctx, NK_KEY_TEXT_UNDO, down);\n            else if (*code == 'r' && (evt->xkey.state & ControlMask))\n                nk_input_key(&rawfb->ctx, NK_KEY_TEXT_REDO, down);\n            else if (*code == XK_Left && (evt->xkey.state & ControlMask))\n                nk_input_key(&rawfb->ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else if (*code == XK_Right && (evt->xkey.state & ControlMask))\n                nk_input_key(&rawfb->ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else if (*code == 'b' && (evt->xkey.state & ControlMask))\n                nk_input_key(&rawfb->ctx, NK_KEY_TEXT_LINE_START, down);\n            else if (*code == 'e' && (evt->xkey.state & ControlMask))\n                nk_input_key(&rawfb->ctx, NK_KEY_TEXT_LINE_END, down);\n            else {\n                if (*code == 'i')\n                    nk_input_key(&rawfb->ctx, NK_KEY_TEXT_INSERT_MODE, down);\n                else if (*code == 'r')\n                    nk_input_key(&rawfb->ctx, NK_KEY_TEXT_REPLACE_MODE, down);\n                if (down) {\n                    char buf[32];\n                    KeySym keysym = 0;\n                    if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)\n                        nk_input_glyph(&rawfb->ctx, buf);\n                }\n            }\n        } XFree(code);\n        return 1;\n    } else if (evt->type == ButtonPress || evt->type == ButtonRelease) {\n        /* Button handler */\n        int down = (evt->type == ButtonPress);\n        const int x = evt->xbutton.x, y = evt->xbutton.y;\n        if (evt->xbutton.button == Button1)\n            nk_input_button(&rawfb->ctx, NK_BUTTON_LEFT, x, y, down);\n        if (evt->xbutton.button == Button2)\n            nk_input_button(&rawfb->ctx, NK_BUTTON_MIDDLE, x, y, down);\n        else if (evt->xbutton.button == Button3)\n            nk_input_button(&rawfb->ctx, NK_BUTTON_RIGHT, x, y, down);\n        else if (evt->xbutton.button == Button4)\n            nk_input_scroll(&rawfb->ctx, nk_vec2(0, 1.0f));\n        else if (evt->xbutton.button == Button5)\n            nk_input_scroll(&rawfb->ctx, nk_vec2(0, -1.0f));\n        else if (evt->xbutton.button == 8)\n            nk_input_button(&rawfb->ctx, NK_BUTTON_X1, x, y, down);\n        else if (evt->xbutton.button == 9)\n            nk_input_button(&rawfb->ctx, NK_BUTTON_X2, x, y, down);\n        else return 0;\n        return 1;\n    } else if (evt->type == MotionNotify) {\n        /* Mouse motion handler */\n        const int x = evt->xmotion.x, y = evt->xmotion.y;\n        nk_input_motion(&rawfb->ctx, x, y);\n        if (rawfb->ctx.input.mouse.grabbed) {\n            rawfb->ctx.input.mouse.pos.x = rawfb->ctx.input.mouse.prev.x;\n            rawfb->ctx.input.mouse.pos.y = rawfb->ctx.input.mouse.prev.y;\n            XWarpPointer(xlib.dpy, None, xlib.root, 0, 0, 0, 0, (int)rawfb->ctx.input.mouse.pos.x, (int)rawfb->ctx.input.mouse.pos.y);\n        } return 1;\n    } else if (evt->type == Expose || evt->type == ConfigureNotify) {\n        /* Window resize handler */\n        void *fb;\n        struct rawfb_pl pl;\n        unsigned int width, height;\n        XWindowAttributes attr;\n        XGetWindowAttributes(dpy, win, &attr);\n\n        width = (unsigned int)attr.width;\n        height = (unsigned int)attr.height;\n\n        nk_xlib_shutdown();\n        nk_xlib_init(dpy, XDefaultVisual(dpy, screen), screen, win, width, height, &fb, &pl);\n        nk_rawfb_resize_fb(rawfb, fb, width, height, width * 4, pl);\n    } else if (evt->type == KeymapNotify) {\n        XRefreshKeyboardMapping(&evt->xmapping);\n        return 1;\n    } else if (evt->type == LeaveNotify) {\n        XUndefineCursor(xlib.dpy, xlib.root);\n    } else if (evt->type == EnterNotify) {\n        XDefineCursor(xlib.dpy, xlib.root, xlib.cursor);\n    } return 0;\n}\n\nNK_API void\nnk_xlib_shutdown(void)\n{\n    XFreeCursor(xlib.dpy, xlib.cursor);\n    if (xlib.fallback) {\n        free(xlib.ximg->data);\n        XDestroyImage(xlib.ximg);\n    } else {\n        XShmDetach(xlib.dpy, &xlib.xsi);\n        XDestroyImage(xlib.ximg);\n        shmdt(xlib.xsi.shmaddr);\n        shmctl(xlib.xsi.shmid, IPC_RMID, NULL);\n    } memset(&xlib, 0, sizeof(xlib));\n}\n\nNK_API void\nnk_xlib_render(Drawable screen)\n{\n    if (xlib.fallback)\n        XPutImage(xlib.dpy, screen, xlib.gc, xlib.ximg,\n            0, 0, 0, 0, xlib.ximg->width, xlib.ximg->height);\n    else XShmPutImage(xlib.dpy, screen, xlib.gc, xlib.ximg,\n            0, 0, 0, 0, xlib.ximg->width, xlib.ximg->height, False);\n}\n#endif\n\n"
  },
  {
    "path": "demo/sdl3_renderer/Makefile",
    "content": "# this Makefile is specific to GNU Make and GCC'compatible compilers\n\nPKG_CONFIG := $(or\\\n    $(shell pkg-config --version >/dev/null 2>/dev/null && echo pkg-config),\\\n    $(shell command -v pkg-config 2>/dev/null),\\\n    $(error missing pkg-config utility!))\n\nPKG_SDL3 := $(or\\\n    $(and $(shell ${PKG_CONFIG} sdl3 --path 2>/dev/null),sdl3),\\\n    $(shell ${PKG_CONFIG} sdl3 --exists 2>/dev/null && echo sdl3),\\\n    $(error pkg-config was unable to find: sdl3))\n\nOSNAME := $(or\\\n    $(and ${EMSCRIPTEN}, Emscripten),\\\n    ${OS},\\\n    $(shell uname -s),\\\n    $(error could not detect OSNAME))\n\nbinext_Windows_NT := .exe\nbinext_Emscripten := .html\nBINEXT := ${binext_${OSNAME}}\n\nTEMPDIR := ./bin\nBIN := ${TEMPDIR}/demo${BINEXT}\n\ncflags += -std=c89 -Wall -Wextra -Wpedantic\ncflags += -O2\n#cflags += -O0 -g\n#cflags += -fsanitize=address\n#cflags += -fsanitize=undefined\ncflags += ${CFLAGS}\n\ncppflags += $(shell ${PKG_CONFIG} ${PKG_SDL3} --cflags --keep-system-cflags)\ncppflags += ${CPPFLAGS}\n\nldflags += $(shell ${PKG_CONFIG} ${PKG_SDL3} --libs-only-L --libs-only-other --keep-system-libs)\nldflags += ${LDFLAGS}\n\nldlibs += $(shell ${PKG_CONFIG} ${PKG_SDL3} --libs-only-l --keep-system-libs)\nldlibs += -lm\nldlibs += ${LDLIBS}\n# HACK: this one is for compatibility with other demos\nldlibs += ${LIBS}\n\nDEP := ${TEMPDIR}/$(notdir ${BIN}).d\n\nSRC := main.c\n\n${BIN}:\n\tmkdir -p $(dir $@)\n\t${CC} ${SRC} -o $@ -MD -MF ${DEP} ${cppflags} ${ldflags} ${ldlibs} ${cflags}\n\n${BIN}: ${SRC}\n\n-include ${DEP}\n\n"
  },
  {
    "path": "demo/sdl3_renderer/main.c",
    "content": "/* nuklear - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <limits.h>\n#include <time.h>\n\n#include <SDL3/SDL.h>\n\n/* This demo uses \"main callbacks\" which are new in SDL3\n * Those provide highly portable entry point and event loop for the app\n * see: https://wiki.libsdl.org/SDL3/README-main-functions\n * */\n#define SDL_MAIN_USE_CALLBACKS\n#include <SDL3/SDL_main.h>\n\n/* ===============================================================\n *\n *                          CONFIG\n *\n * ===============================================================*/\n\n/* optional: sdl3_renderer does not need any of these defines\n * (but some examples might need them, so be careful) */\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_STANDARD_IO\n\n/* note that sdl3_renderer comes with nk_sdl_style_set_debug_font()\n * so you may wish to use that instead of font baking */\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n\n/* note that sdl3_renderer comes with nk_sdl_allocator()\n * and you probably want to use that allocator instead of the default ones */\n/*#define NK_INCLUDE_DEFAULT_ALLOCATOR*/\n\n/* mandatory: sdl3_renderer depends on those defines */\n#define NK_INCLUDE_COMMAND_USERDATA\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n\n\n/* We can re-use the types provided by SDL which are extremely portable,\n * so there is no need for Nuklear to detect those on its own */\n/*#define NK_INCLUDE_FIXED_TYPES*/\n#ifndef NK_INCLUDE_FIXED_TYPES\n    #define NK_INT8              Sint8\n    #define NK_UINT8             Uint8\n    #define NK_INT16             Sint16\n    #define NK_UINT16            Uint16\n    #define NK_INT32             Sint32\n    #define NK_UINT32            Uint32\n    /* SDL guarantees 'uintptr_t' typedef */\n    #define NK_SIZE_TYPE         uintptr_t\n    #define NK_POINTER_TYPE      uintptr_t\n#endif\n\n/* We can reuse the `bool` symbol because SDL3 guarantees its existence */\n/*#define NK_INCLUDE_STANDARD_BOOL*/\n#ifndef NK_INCLUDE_STANDARD_BOOL\n    #define NK_BOOL               bool\n#endif\n\n/* We can re-use various portable libc functions provided by SDL */\n#define NK_ASSERT(condition)      SDL_assert(condition)\n#define NK_STATIC_ASSERT(exp)     SDL_COMPILE_TIME_ASSERT(, exp)\n#define NK_MEMSET(dst, c, len)    SDL_memset(dst, c, len)\n#define NK_MEMCPY(dst, src, len)  SDL_memcpy(dst, src, len)\n#define NK_VSNPRINTF(s, n, f, a)  SDL_vsnprintf(s, n, f, a)\n#define NK_STRTOD(str, endptr)    SDL_strtod(str, endptr)\n\n/* SDL3 does not provide \"dtoa\" (only integer versions)\n * but we can emulate it with SDL_snprintf */\nstatic char* nk_sdl_dtoa(char *str, double d);\n#define NK_DTOA(str, d) nk_sdl_dtoa(str, d)\n\n/* SDL can also provide us with math functions, but beware that Nuklear's own\n * implementation can be slightly faster at the cost of some precision */\n#define NK_INV_SQRT(f)            (1.0f / SDL_sqrtf(f))\n#define NK_SIN(f)                 SDL_sinf(f)\n#define NK_COS(f)                 SDL_cosf(f)\n\n/* HACK: Nuklear pulls two stb libraries in order to use font baking\n * those libraries pull in some libc headers internally, creating a linkage dependency,\n * so you’ll most likely want to use SDL symbols instead */\n#define STBTT_ifloor(x)       ((int)SDL_floor(x))\n#define STBTT_iceil(x)        ((int)SDL_ceil(x))\n#define STBTT_sqrt(x)         SDL_sqrt(x)\n#define STBTT_pow(x,y)        SDL_pow(x,y)\n#define STBTT_fmod(x,y)       SDL_fmod(x,y)\n#define STBTT_cos(x)          SDL_cosf(x)\n#define STBTT_acos(x)         SDL_acos(x)\n#define STBTT_fabs(x)         SDL_fabs(x)\n#define STBTT_assert(x)       SDL_assert(x)\n#define STBTT_strlen(x)       SDL_strlen(x)\n#define STBTT_memcpy          SDL_memcpy\n#define STBTT_memset          SDL_memset\n#define stbtt_uint8           Uint8\n#define stbtt_int8            Sint8\n#define stbtt_uint16          Uint16\n#define stbtt_int16           Sint16\n#define stbtt_uint32          Uint32\n#define stbtt_int32           Sint32\n#define STBRP_SORT            SDL_qsort\n#define STBRP_ASSERT          SDL_assert\n/* There is no need to define STBTT_malloc/STBTT_free macros\n * Nuklear will define those to user-provided nk_allocator */\n\n\n#define NK_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#define NK_SDL3_RENDERER_IMPLEMENTATION\n#include \"nuklear_sdl3_renderer.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* These are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n    #define INCLUDE_STYLE\n    #define INCLUDE_CALCULATOR\n    #define INCLUDE_CANVAS\n    #define INCLUDE_OVERVIEW\n    #define INCLUDE_CONFIGURATOR\n    #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n    #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n    #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n    #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n    #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n    #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n    #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\n\nstruct nk_sdl_app {\n    SDL_Window* window;\n    SDL_Renderer* renderer;\n    struct nk_context * ctx;\n    struct nk_colorf bg;\n    enum nk_anti_aliasing AA;\n};\n\nstatic SDL_AppResult\nnk_sdl_fail()\n{\n    SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, \"Error: %s\", SDL_GetError());\n    return SDL_APP_FAILURE;\n}\n\nSDL_AppResult\nSDL_AppInit(void** appstate, int argc, char* argv[])\n{\n    struct nk_sdl_app* app;\n    struct nk_context* ctx;\n    float font_scale;\n    NK_UNUSED(argc);\n    NK_UNUSED(argv);\n\n    if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {\n        return nk_sdl_fail();\n    }\n\n    app = SDL_malloc(sizeof(*app));\n    if (app == NULL) {\n        return nk_sdl_fail();\n    }\n\n    if (!SDL_CreateWindowAndRenderer(\"Nuklear: SDL3 Renderer\", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &app->window, &app->renderer)) {\n        SDL_free(app);\n        return nk_sdl_fail();\n    }\n    *appstate = app;\n\n    if (!SDL_SetRenderVSync(app->renderer, 1)) {\n        SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, \"SDL_SetRenderVSync failed: %s\", SDL_GetError());\n    }\n\n    app->bg.r = 0.10f;\n    app->bg.g = 0.18f;\n    app->bg.b = 0.24f;\n    app->bg.a = 1.0f;\n\n\n    font_scale = 1;\n    {\n        /* This scaling logic was kept simple for the demo purpose.\n         * On some platforms, this might not be the exact scale\n         * that you want to use. For more information, see:\n         * https://wiki.libsdl.org/SDL3/README-highdpi */\n        const float scale = SDL_GetWindowDisplayScale(app->window);\n        SDL_SetRenderScale(app->renderer, scale, scale);\n        font_scale = scale;\n    }\n\n    ctx = nk_sdl_init(app->window, app->renderer, nk_sdl_allocator());\n    app->ctx = ctx;\n\n#if 0\n    {\n        /* If you don't want to use advanced Nuklear font baking API\n         * you can use simple ASCII debug font provided by SDL\n         * just change the `#if 0` above to `#if 1` */\n        nk_sdl_style_set_debug_font(ctx);\n\n        /* Note that since debug font is extremely small (only 8x8 pixels),\n         * scaling it does not make much sense. The font would appear blurry. */\n        NK_UNUSED(font_scale);\n\n        /* You may wish to change a few style options, here are few recommendations: */\n        ctx->style.button.rounding = 0.0f;\n        ctx->style.menu_button.rounding = 0.0f;\n        ctx->style.property.rounding = 0.0f;\n        ctx->style.property.border = 0.0f;\n        ctx->style.option.border = -1.0f;\n        ctx->style.checkbox.border = -1.0f;\n        ctx->style.property.dec_button.border = -2.0f;\n        ctx->style.property.inc_button.border = -2.0f;\n        ctx->style.tab.tab_minimize_button.border = -2.0f;\n        ctx->style.tab.tab_maximize_button.border = -2.0f;\n        ctx->style.tab.node_minimize_button.border = -2.0f;\n        ctx->style.tab.node_maximize_button.border = -2.0f;\n        ctx->style.checkbox.spacing = 5.0f;\n\n        /* It's better to disable anti-aliasing when using small fonts */\n        app->AA = NK_ANTI_ALIASING_OFF;\n    }\n#else\n    {\n        struct nk_font_atlas *atlas;\n        struct nk_font_config config = nk_font_config(0);\n        struct nk_font *font;\n\n        /* set up the font atlas and add desired font; note that font sizes are\n         * multiplied by font_scale to produce better results at higher DPIs */\n        atlas = nk_sdl_font_stash_begin(ctx);\n        font = nk_font_atlas_add_default(atlas, 13 * font_scale, &config);\n        /*font = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/DroidSans.ttf\", 14 * font_scale, &config);*/\n        /*font = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Roboto-Regular.ttf\", 16 * font_scale, &config);*/\n        /*font = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/kenvector_future_thin.ttf\", 13 * font_scale, &config);*/\n        /*font = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyClean.ttf\", 12 * font_scale, &config);*/\n        /*font = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyTiny.ttf\", 10 * font_scale, &config);*/\n        /*font = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Cousine-Regular.ttf\", 13 * font_scale, &config);*/\n        nk_sdl_font_stash_end(ctx);\n\n        /* this hack makes the font appear to be scaled down to the desired\n         * size and is only necessary when font_scale > 1 */\n        font->handle.height /= font_scale;\n        /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n        nk_style_set_font(ctx, &font->handle);\n\n        app->AA = NK_ANTI_ALIASING_ON;\n    }\n#endif\n\n    nk_input_begin(ctx);\n\n    return SDL_APP_CONTINUE;\n}\n\nSDL_AppResult\nSDL_AppEvent(void *appstate, SDL_Event* event)\n{\n    struct nk_sdl_app* app = (struct nk_sdl_app*)appstate;\n\n    switch (event->type) {\n        case SDL_EVENT_QUIT:\n            return SDL_APP_SUCCESS;\n        case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:\n            /* You may wish to rescale the renderer and Nuklear during this event.\n             * Without this the UI and Font could appear too small or too big.\n             * This is not handled by the demo in order to keep it simple,\n             * but you may wish to re-bake the Font whenever this happens. */\n            SDL_Log(\"Unhandled scale event! Nuklear may appear blurry\");\n            return SDL_APP_CONTINUE;\n    }\n\n    /* Remember to always rescale the event coordinates,\n     * if your renderer uses custom scale. */\n    SDL_ConvertEventToRenderCoordinates(app->renderer, event);\n\n    nk_sdl_handle_event(app->ctx, event);\n\n    return SDL_APP_CONTINUE;\n}\n\nSDL_AppResult\nSDL_AppIterate(void *appstate)\n{\n    struct nk_sdl_app* app = (struct nk_sdl_app*)appstate;\n    struct nk_context* ctx = app->ctx;\n\n#ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    NK_MEMCPY(color_table, nk_default_color_style, sizeof(color_table));\n#endif\n\n    nk_input_end(ctx);\n\n    /* GUI */\n    if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n        NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n        NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n    {\n        enum {EASY, HARD};\n        static int op = EASY;\n        static int property = 20;\n\n        nk_layout_row_static(ctx, 30, 80, 1);\n        if (nk_button_label(ctx, \"button\")) {\n            SDL_Log(\"button pressed\");\n        }\n        nk_layout_row_dynamic(ctx, 30, 2);\n        if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n        if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n        nk_layout_row_dynamic(ctx, 25, 1);\n        nk_property_int(ctx, \"Compression:\", 0, &property, 1000, 1, 1);\n\n        nk_layout_row_dynamic(ctx, 20, 1);\n        nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n        nk_layout_row_dynamic(ctx, 25, 1);\n        if (nk_combo_begin_color(ctx, nk_rgb_cf(app->bg), nk_vec2(nk_widget_width(ctx),400))) {\n            nk_layout_row_dynamic(ctx, 120, 1);\n            app->bg = nk_color_picker(ctx, app->bg, NK_RGBA);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            app->bg.r = nk_propertyf(ctx, \"#R:\", 0, app->bg.r, 1.0f, 0.01f,0.005f);\n            app->bg.g = nk_propertyf(ctx, \"#G:\", 0, app->bg.g, 1.0f, 0.01f,0.005f);\n            app->bg.b = nk_propertyf(ctx, \"#B:\", 0, app->bg.b, 1.0f, 0.01f,0.005f);\n            app->bg.a = nk_propertyf(ctx, \"#A:\", 0, app->bg.a, 1.0f, 0.01f,0.005f);\n            nk_combo_end(ctx);\n        }\n    }\n    nk_end(ctx);\n\n    /* -------------- EXAMPLES ---------------- */\n    #ifdef INCLUDE_CALCULATOR\n        calculator(ctx);\n    #endif\n    #ifdef INCLUDE_CANVAS\n        canvas(ctx);\n    #endif\n    #ifdef INCLUDE_OVERVIEW\n        overview(ctx);\n    #endif\n    #ifdef INCLUDE_CONFIGURATOR\n        style_configurator(ctx, color_table);\n    #endif\n    #ifdef INCLUDE_NODE_EDITOR\n        node_editor(ctx);\n    #endif\n    /* ----------------------------------------- */\n\n    SDL_SetRenderDrawColorFloat(app->renderer, app->bg.r, app->bg.g, app->bg.b, app->bg.a);\n    SDL_RenderClear(app->renderer);\n\n    nk_sdl_render(ctx, app->AA);\n    nk_sdl_update_TextInput(ctx);\n\n    /* show if TextInput is active for debug purpose. Feel free to remove this. */\n    SDL_SetRenderDrawColor(app->renderer, 0xFF, 0xFF, 0xFF, 0xFF);\n    SDL_RenderDebugTextFormat(app->renderer, 10, 10, \"TextInputActive? %s\",\n                              SDL_TextInputActive(app->window) ? \"Yes\" : \"No\");\n\n    SDL_RenderPresent(app->renderer);\n\n    nk_input_begin(ctx);\n    return SDL_APP_CONTINUE;\n}\n\nvoid\nSDL_AppQuit(void* appstate, SDL_AppResult result)\n{\n    struct nk_sdl_app* app = (struct nk_sdl_app*)appstate;\n    NK_UNUSED(result);\n\n    if (app) {\n        nk_input_end(app->ctx);\n        nk_sdl_shutdown(app->ctx);\n        SDL_DestroyRenderer(app->renderer);\n        SDL_DestroyWindow(app->window);\n        SDL_free(app);\n    }\n}\n\nstatic char*\nnk_sdl_dtoa(char *str, double d)\n{\n    NK_ASSERT(str);\n    if (!str) return NULL;\n    (void)SDL_snprintf(str, 99999, \"%.17g\", d);\n    return str;\n}\n\n"
  },
  {
    "path": "demo/sdl3_renderer/nuklear_sdl3_renderer.h",
    "content": "/* nuklear - public domain */\n\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n\n#ifndef NK_SDL3_RENDERER_H_\n#define NK_SDL3_RENDERER_H_\n\n#if SDL_MAJOR_VERSION < 3\n    #error \"nk_sdl3_renderer requires at least SDL 3.0.0\"\n#endif\n#ifndef NK_INCLUDE_COMMAND_USERDATA\n    #error \"nk_sdl3_renderer requires the NK_INCLUDE_COMMAND_USERDATA define\"\n#endif\n#ifndef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n    #error \"nk_sdl3_renderer requires the NK_INCLUDE_VERTEX_BUFFER_OUTPUT define\"\n#endif\n\n/* We have to redefine it because demos do not include any headers\n * This is the same default value as the one from \"src/nuklear_internal.h\" */\n#ifndef NK_BUFFER_DEFAULT_INITIAL_SIZE\n    #define NK_BUFFER_DEFAULT_INITIAL_SIZE (4*1024)\n#endif\n\nNK_API struct nk_context*   nk_sdl_init(SDL_Window *win, SDL_Renderer *renderer, struct nk_allocator allocator);\n#ifdef NK_INCLUDE_FONT_BAKING\nNK_API struct nk_font_atlas* nk_sdl_font_stash_begin(struct nk_context* ctx);\nNK_API void                 nk_sdl_font_stash_end(struct nk_context* ctx);\n#endif\nNK_API int                  nk_sdl_handle_event(struct nk_context* ctx, SDL_Event *evt);\nNK_API void                 nk_sdl_render(struct nk_context* ctx, enum nk_anti_aliasing);\nNK_API void                 nk_sdl_update_TextInput(struct nk_context* ctx);\nNK_API void                 nk_sdl_shutdown(struct nk_context* ctx);\nNK_API nk_handle            nk_sdl_get_userdata(struct nk_context* ctx);\nNK_API void                 nk_sdl_set_userdata(struct nk_context* ctx, nk_handle userdata);\nNK_API void                 nk_sdl_style_set_debug_font(struct nk_context* ctx);\nNK_API struct nk_allocator  nk_sdl_allocator(void);\n\n#endif /* NK_SDL3_RENDERER_H_ */\n\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_SDL3_RENDERER_IMPLEMENTATION\n#ifndef NK_SDL3_RENDERER_IMPLEMENTATION_ONCE\n#define NK_SDL3_RENDERER_IMPLEMENTATION_ONCE\n\n#ifndef NK_SDL_DOUBLE_CLICK_LO\n#define NK_SDL_DOUBLE_CLICK_LO 0.02\n#endif\n#ifndef NK_SDL_DOUBLE_CLICK_HI\n#define NK_SDL_DOUBLE_CLICK_HI 0.2\n#endif\n\nstruct nk_sdl_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    SDL_Texture *font_tex;\n};\n\nstruct nk_sdl_vertex {\n    float position[2];\n    float uv[2];\n    float col[4];\n};\n\nstruct nk_sdl {\n    SDL_Window *win;\n    SDL_Renderer *renderer;\n    struct nk_user_font* debug_font;\n    struct nk_sdl_device ogl;\n    struct nk_context ctx;\n#ifdef NK_INCLUDE_FONT_BAKING\n    struct nk_font_atlas atlas;\n#endif\n    struct nk_allocator allocator;\n    nk_handle userdata;\n    Uint64 last_left_click;\n    Uint64 last_render;\n    bool insert_toggle;\n    bool edit_was_active;\n};\n\nNK_API nk_handle\nnk_sdl_get_userdata(struct nk_context* ctx) {\n    struct nk_sdl* sdl;\n    NK_ASSERT(ctx);\n    sdl = (struct nk_sdl*)ctx->userdata.ptr;\n    NK_ASSERT(sdl);\n    return sdl->userdata;\n}\n\nNK_API void\nnk_sdl_set_userdata(struct nk_context* ctx, nk_handle userdata) {\n    struct nk_sdl* sdl;\n    NK_ASSERT(ctx);\n    sdl = (struct nk_sdl*)ctx->userdata.ptr;\n    NK_ASSERT(sdl);\n    sdl->userdata = userdata;\n}\n\nNK_INTERN void *\nnk_sdl_alloc(nk_handle user, void *old, nk_size size)\n{\n    NK_UNUSED(user);\n    /* FIXME: nk_sdl_alloc should use SDL_realloc here, not SDL_malloc\n     * but this could cause a double-free due to bug within Nuklear, see:\n     * https://github.com/Immediate-Mode-UI/Nuklear/issues/768\n     * */\n#if 0\n    return SDL_realloc(old, size);\n#else\n    NK_UNUSED(old);\n    return SDL_malloc(size);\n#endif\n}\n\nNK_INTERN void\nnk_sdl_free(nk_handle user, void *old)\n{\n    NK_UNUSED(user);\n    SDL_free(old);\n}\n\nNK_API struct nk_allocator\nnk_sdl_allocator()\n{\n    struct nk_allocator allocator;\n    allocator.userdata.ptr = 0;\n    allocator.alloc = nk_sdl_alloc;\n    allocator.free = nk_sdl_free;\n    return allocator;\n}\n\nNK_INTERN void\nnk_sdl_device_upload_atlas(struct nk_context* ctx, const void *image, int width, int height)\n{\n    struct nk_sdl* sdl;\n    NK_ASSERT(ctx);\n    NK_ASSERT(image);\n    NK_ASSERT(width > 0);\n    NK_ASSERT(height > 0);\n\n    sdl = (struct nk_sdl*)ctx->userdata.ptr;\n    NK_ASSERT(sdl);\n\n    /* Clean up if the texture already exists. */\n    if (sdl->ogl.font_tex != NULL) {\n        SDL_DestroyTexture(sdl->ogl.font_tex);\n        sdl->ogl.font_tex = NULL;\n    }\n\n    sdl->ogl.font_tex = SDL_CreateTexture(sdl->renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height);\n    NK_ASSERT(sdl->ogl.font_tex);\n    SDL_UpdateTexture(sdl->ogl.font_tex, NULL, image, 4 * width);\n    SDL_SetTextureBlendMode(sdl->ogl.font_tex, SDL_BLENDMODE_BLEND);\n}\n\nNK_API void\nnk_sdl_update_TextInput(struct nk_context* ctx)\n{\n    struct nk_sdl* sdl;\n    bool active;\n    NK_ASSERT(ctx);\n    sdl = (struct nk_sdl*)ctx->userdata.ptr;\n    NK_ASSERT(sdl);\n\n    /* Determine if Nuklear is using any top-level \"edit\" widget.\n     * Popups take higher priority because they block any incomming input.\n     * This will not work, if the widget is not updating context state properly. */\n    if (!ctx->active)\n        active = false;\n    else if (ctx->active->popup.win)\n        active = ctx->active->popup.win->edit.active;\n    else\n        active = ctx->active->edit.active;\n\n    /* decide, if TextInputActive should be unchanged/stoped/started\n     * and change its state accordingly for owned SDL Window */\n    if (active != sdl->edit_was_active)\n    {\n        const bool window_edit_active = SDL_TextInputActive(sdl->win);\n\n        /* If you ever hit this check, it means that the demo and your app\n         * (or something else) are all trying to manage TextInputActive state.\n         * This can cause subtle bugs where the state won't be what you expect.\n         * You can safely remove this assert and the demo will keep working,\n         * but make sure it does not cause any issues for you */\n        NK_ASSERT(window_edit_active == sdl->edit_was_active && \"something else changed TextInputActive state for this Window\");\n\n        if (!window_edit_active && !sdl->edit_was_active && active)\n            SDL_StartTextInput(sdl->win);\n        else if (window_edit_active && sdl->edit_was_active && !active)\n            SDL_StopTextInput(sdl->win);\n        sdl->edit_was_active = active;\n    }\n\n    /* FIXME:\n     * for full SDL3 integration, you also need to find current edit widget\n     * bounds and the text cursor offset, and pass this data into SDL_SetTextInputArea.\n     * This is currently not possible to do safely as Nuklear does not support it.\n     * https://wiki.libsdl.org/SDL3/SDL_SetTextInputArea\n     * https://github.com/Immediate-Mode-UI/Nuklear/pull/857\n     */\n}\n\nNK_API void\nnk_sdl_render(struct nk_context* ctx, enum nk_anti_aliasing AA)\n{\n    /* setup global state */\n    struct nk_sdl* sdl;\n    NK_ASSERT(ctx);\n    sdl = (struct nk_sdl*)ctx->userdata.ptr;\n    NK_ASSERT(sdl);\n\n    { /* setup internal delta time that Nuklear needs for animations */\n        const Uint64 ticks = SDL_GetTicks();\n        ctx->delta_time_seconds = (float)(ticks - sdl->last_render) / 1000.0f;\n        sdl->last_render = ticks;\n    }\n\n    {\n        SDL_Rect saved_clip;\n        bool clipping_enabled;\n        int vs = sizeof(struct nk_sdl_vertex);\n        size_t vp = NK_OFFSETOF(struct nk_sdl_vertex, position);\n        size_t vt = NK_OFFSETOF(struct nk_sdl_vertex, uv);\n        size_t vc = NK_OFFSETOF(struct nk_sdl_vertex, col);\n\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        const nk_draw_index *offset = NULL;\n        struct nk_buffer vbuf, ebuf;\n\n        /* fill converting configuration */\n        struct nk_convert_config config;\n        static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n            {NK_VERTEX_POSITION,    NK_FORMAT_FLOAT,                NK_OFFSETOF(struct nk_sdl_vertex, position)},\n            {NK_VERTEX_TEXCOORD,    NK_FORMAT_FLOAT,                NK_OFFSETOF(struct nk_sdl_vertex, uv)},\n            {NK_VERTEX_COLOR,       NK_FORMAT_R32G32B32A32_FLOAT,   NK_OFFSETOF(struct nk_sdl_vertex, col)},\n            {NK_VERTEX_LAYOUT_END}\n        };\n        NK_MEMSET(&config, 0, sizeof(config));\n        config.vertex_layout = vertex_layout;\n        config.vertex_size = sizeof(struct nk_sdl_vertex);\n        config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);\n        config.tex_null = sdl->ogl.tex_null;\n        config.circle_segment_count = 22;\n        config.curve_segment_count = 22;\n        config.arc_segment_count = 22;\n        config.global_alpha = 1.0f;\n        config.shape_AA = AA;\n        config.line_AA = AA;\n\n        /* convert shapes into vertexes */\n        nk_buffer_init(&vbuf, &sdl->allocator, NK_BUFFER_DEFAULT_INITIAL_SIZE);\n        nk_buffer_init(&ebuf, &sdl->allocator, NK_BUFFER_DEFAULT_INITIAL_SIZE);\n        nk_convert(&sdl->ctx, &sdl->ogl.cmds, &vbuf, &ebuf, &config);\n\n        /* iterate over and execute each draw command */\n        offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);\n\n        clipping_enabled = SDL_RenderClipEnabled(sdl->renderer);\n        SDL_GetRenderClipRect(sdl->renderer, &saved_clip);\n\n        nk_draw_foreach(cmd, &sdl->ctx, &sdl->ogl.cmds)\n        {\n            if (!cmd->elem_count) continue;\n\n            {\n                SDL_Rect r;\n                r.x = cmd->clip_rect.x;\n                r.y = cmd->clip_rect.y;\n                r.w = cmd->clip_rect.w;\n                r.h = cmd->clip_rect.h;\n                SDL_SetRenderClipRect(sdl->renderer, &r);\n            }\n\n            {\n                const void *vertices = nk_buffer_memory_const(&vbuf);\n\n                SDL_RenderGeometryRaw(\n                        sdl->renderer,\n                        (SDL_Texture *)cmd->texture.ptr,\n                        (const float*)((const nk_byte*)vertices + vp), vs,\n                        (const SDL_FColor*)((const nk_byte*)vertices + vc), vs,\n                        (const float*)((const nk_byte*)vertices + vt), vs,\n                        (vbuf.needed / vs),\n                        (void *) offset, cmd->elem_count, 2);\n\n                offset += cmd->elem_count;\n            }\n        }\n\n        SDL_SetRenderClipRect(sdl->renderer, &saved_clip);\n        if (!clipping_enabled) {\n            SDL_SetRenderClipRect(sdl->renderer, NULL);\n        }\n\n        nk_clear(&sdl->ctx);\n        nk_buffer_clear(&sdl->ogl.cmds);\n        nk_buffer_free(&vbuf);\n        nk_buffer_free(&ebuf);\n    }\n}\n\nNK_INTERN void\nnk_sdl_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    char *text;\n    int len;\n    NK_UNUSED(usr);\n\n    /* this function returns empty string on failure, not NULL */\n    text = SDL_GetClipboardText();\n    NK_ASSERT(text);\n\n    if (text[0] != '\\0') {\n        /* FIXME: there is a bug in Nuklear that affects UTF8 clipboard handling\n         * \"len\" should be a buffer length, but due to bug it must be a glyph count\n         * see: https://github.com/Immediate-Mode-UI/Nuklear/pull/841 */\n#if 0\n        len = nk_strlen(text);\n#else\n        len = SDL_utf8strlen(text);\n#endif\n        nk_textedit_paste(edit, text, len);\n    }\n    SDL_free(text);\n}\n\nNK_INTERN void\nnk_sdl_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    const char *ptext;\n    char *str;\n    size_t buflen;\n    int i;\n    struct nk_sdl* sdl = (struct nk_sdl*)usr.ptr;\n    NK_ASSERT(sdl);\n    if (len <= 0 || text == NULL) return;\n\n    /* FIXME: there is a bug in Nuklear that affects UTF8 clipboard handling\n     * \"len\" is expected to be a buffer length, but due to bug it actually is a glyph count\n     * see: https://github.com/Immediate-Mode-UI/Nuklear/pull/841 */\n#if 0\n    buflen = len + 1;\n    NK_UNUSED(ptext);\n#else\n    ptext = text;\n    for (i = len; i > 0; i--)\n        (void)SDL_StepUTF8(&ptext, NULL);\n    buflen = (size_t)(ptext - text) + 1;\n#endif\n\n    str = sdl->allocator.alloc(sdl->allocator.userdata, 0, buflen);\n    if (!str) return;\n    SDL_strlcpy(str, text, buflen);\n    SDL_SetClipboardText(str);\n    sdl->allocator.free(sdl->allocator.userdata, str);\n}\n\nNK_API struct nk_context*\nnk_sdl_init(SDL_Window *win, SDL_Renderer *renderer, struct nk_allocator allocator)\n{\n    struct nk_sdl* sdl;\n    NK_ASSERT(win);\n    NK_ASSERT(renderer);\n    NK_ASSERT(allocator.alloc);\n    NK_ASSERT(allocator.free);\n    sdl = allocator.alloc(allocator.userdata, 0, sizeof(*sdl));\n    NK_ASSERT(sdl);\n    SDL_zerop(sdl);\n    sdl->allocator.userdata = allocator.userdata;\n    sdl->allocator.alloc = allocator.alloc;\n    sdl->allocator.free = allocator.free;\n    sdl->win = win;\n    sdl->renderer = renderer;\n    nk_init(&sdl->ctx, &sdl->allocator, 0);\n    sdl->ctx.userdata = nk_handle_ptr((void*)sdl);\n    sdl->ctx.clip.copy = nk_sdl_clipboard_copy;\n    sdl->ctx.clip.paste = nk_sdl_clipboard_paste;\n    sdl->ctx.clip.userdata = nk_handle_ptr((void*)sdl);\n    nk_buffer_init(&sdl->ogl.cmds, &sdl->allocator, NK_BUFFER_DEFAULT_INITIAL_SIZE);\n    sdl->last_left_click = 0;\n    sdl->edit_was_active = false;\n    sdl->insert_toggle = false;\n    return &sdl->ctx;\n}\n\n#ifdef NK_INCLUDE_FONT_BAKING\nNK_API struct nk_font_atlas*\nnk_sdl_font_stash_begin(struct nk_context* ctx)\n{\n    struct nk_sdl* sdl;\n    NK_ASSERT(ctx);\n    sdl = (struct nk_sdl*)ctx->userdata.ptr;\n    NK_ASSERT(sdl);\n    nk_font_atlas_init(&sdl->atlas, &sdl->allocator);\n    nk_font_atlas_begin(&sdl->atlas);\n    return &sdl->atlas;\n}\n#endif\n\n#ifdef NK_INCLUDE_FONT_BAKING\nNK_API void\nnk_sdl_font_stash_end(struct nk_context* ctx)\n{\n    struct nk_sdl* sdl;\n    const void *image; int w, h;\n    NK_ASSERT(ctx);\n    sdl = (struct nk_sdl*)ctx->userdata.ptr;\n    NK_ASSERT(sdl);\n    image = nk_font_atlas_bake(&sdl->atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    NK_ASSERT(image);\n    nk_sdl_device_upload_atlas(&sdl->ctx, image, w, h);\n    nk_font_atlas_end(&sdl->atlas, nk_handle_ptr(sdl->ogl.font_tex), &sdl->ogl.tex_null);\n    if (sdl->atlas.default_font) {\n        nk_style_set_font(&sdl->ctx, &sdl->atlas.default_font->handle);\n    }\n}\n#endif\n\nNK_API int\nnk_sdl_handle_event(struct nk_context* ctx, SDL_Event *evt)\n{\n    struct nk_sdl* sdl;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(evt);\n\n    sdl = (struct nk_sdl*)ctx->userdata.ptr;\n    NK_ASSERT(sdl);\n\n    /* We only care about Window currently used by Nuklear */\n    if (sdl->win != SDL_GetWindowFromEvent(evt)) {\n        return 0;\n    }\n\n    switch(evt->type)\n    {\n        case SDL_EVENT_KEY_UP: /* KEYUP & KEYDOWN share same routine */\n        case SDL_EVENT_KEY_DOWN:\n            {\n                int down = evt->type == SDL_EVENT_KEY_DOWN;\n                int ctrl_down = evt->key.mod & (SDL_KMOD_LCTRL | SDL_KMOD_RCTRL);\n\n                /* In 99% of the time, you want to use scancodes, not real key codes,\n                 * see: https://wiki.libsdl.org/SDL3/BestKeyboardPractices */\n                switch(evt->key.scancode)\n                {\n                    case SDL_SCANCODE_RSHIFT: /* RSHIFT & LSHIFT share same routine */\n                    case SDL_SCANCODE_LSHIFT:    nk_input_key(ctx, NK_KEY_SHIFT, down); break;\n                    case SDL_SCANCODE_DELETE:    nk_input_key(ctx, NK_KEY_DEL, down); break;\n                    case SDL_SCANCODE_RETURN:    nk_input_key(ctx, NK_KEY_ENTER, down); break;\n                    case SDL_SCANCODE_TAB:       nk_input_key(ctx, NK_KEY_TAB, down); break;\n                    case SDL_SCANCODE_BACKSPACE: nk_input_key(ctx, NK_KEY_BACKSPACE, down); break;\n                    case SDL_SCANCODE_HOME:      nk_input_key(ctx, NK_KEY_TEXT_START, down);\n                                                 nk_input_key(ctx, NK_KEY_SCROLL_START, down); break;\n                    case SDL_SCANCODE_END:       nk_input_key(ctx, NK_KEY_TEXT_END, down);\n                                                 nk_input_key(ctx, NK_KEY_SCROLL_END, down); break;\n                    case SDL_SCANCODE_PAGEDOWN:  nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); break;\n                    case SDL_SCANCODE_PAGEUP:    nk_input_key(ctx, NK_KEY_SCROLL_UP, down); break;\n                    case SDL_SCANCODE_A:         nk_input_key(ctx, NK_KEY_TEXT_SELECT_ALL, down && ctrl_down); break;\n                    case SDL_SCANCODE_Z:         nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && ctrl_down); break;\n                    case SDL_SCANCODE_R:         nk_input_key(ctx, NK_KEY_TEXT_REDO, down && ctrl_down); break;\n                    case SDL_SCANCODE_C:         nk_input_key(ctx, NK_KEY_COPY, down && ctrl_down); break;\n                    case SDL_SCANCODE_V:         nk_input_key(ctx, NK_KEY_PASTE, down && ctrl_down); break;\n                    case SDL_SCANCODE_X:         nk_input_key(ctx, NK_KEY_CUT, down && ctrl_down); break;\n                    case SDL_SCANCODE_B:         nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && ctrl_down); break;\n                    case SDL_SCANCODE_E:         nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && ctrl_down); break;\n                    case SDL_SCANCODE_UP:        nk_input_key(ctx, NK_KEY_UP, down); break;\n                    case SDL_SCANCODE_DOWN:      nk_input_key(ctx, NK_KEY_DOWN, down); break;\n                    case SDL_SCANCODE_ESCAPE:    nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down); break;\n                    case SDL_SCANCODE_INSERT:\n                        if (down) sdl->insert_toggle = !sdl->insert_toggle;\n                        if (sdl->insert_toggle) {\n                            nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);\n                        } else {\n                            nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);\n                        }\n                        break;\n                    case SDL_SCANCODE_LEFT:\n                        if (ctrl_down)\n                            nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);\n                        else\n                            nk_input_key(ctx, NK_KEY_LEFT, down);\n                        break;\n                    case SDL_SCANCODE_RIGHT:\n                        if (ctrl_down)\n                            nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n                        else\n                            nk_input_key(ctx, NK_KEY_RIGHT, down);\n                        break;\n                    default:\n                        return 0;\n                }\n                return 1;\n            }\n\n        case SDL_EVENT_MOUSE_BUTTON_UP: /* MOUSEBUTTONUP & MOUSEBUTTONDOWN share same routine */\n        case SDL_EVENT_MOUSE_BUTTON_DOWN:\n            {\n                const int x = evt->button.x, y = evt->button.y;\n                const int down = evt->button.down;\n                const double dt = (double)(evt->button.timestamp - sdl->last_left_click) / 1000000000.0;\n                switch(evt->button.button)\n                {\n                    case SDL_BUTTON_LEFT:\n                        nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);\n                        nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y,\n                                down && dt > NK_SDL_DOUBLE_CLICK_LO && dt < NK_SDL_DOUBLE_CLICK_HI);\n                        sdl->last_left_click = evt->button.timestamp;\n                        break;\n                    case SDL_BUTTON_MIDDLE: nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); break;\n                    case SDL_BUTTON_RIGHT:  nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); break;\n                    case SDL_BUTTON_X1:     nk_input_button(ctx, NK_BUTTON_X1, x, y, down); break;\n                    case SDL_BUTTON_X2:     nk_input_button(ctx, NK_BUTTON_X2, x, y, down); break;\n                    default:\n                        return 0;\n                }\n            }\n            return 1;\n\n        case SDL_EVENT_MOUSE_MOTION:\n            ctx->input.mouse.pos.x = evt->motion.x;\n            ctx->input.mouse.pos.y = evt->motion.y;\n            ctx->input.mouse.delta.x = ctx->input.mouse.pos.x - ctx->input.mouse.prev.x;\n            ctx->input.mouse.delta.y = ctx->input.mouse.pos.y - ctx->input.mouse.prev.y;\n            return 1;\n\n        case SDL_EVENT_TEXT_INPUT:\n            {\n                nk_glyph glyph;\n                nk_size len;\n                NK_ASSERT(evt->text.text);\n                len = SDL_strlen(evt->text.text);\n                NK_ASSERT(len <= NK_UTF_SIZE);\n                NK_MEMCPY(glyph, evt->text.text, len);\n                nk_input_glyph(ctx, glyph);\n            }\n            return 1;\n\n        case SDL_EVENT_MOUSE_WHEEL:\n            nk_input_scroll(ctx, nk_vec2(evt->wheel.x, evt->wheel.y));\n            return 1;\n    }\n    return 0;\n}\n\nNK_API\nvoid nk_sdl_shutdown(struct nk_context* ctx)\n{\n    struct nk_sdl* sdl;\n    NK_ASSERT(ctx);\n    sdl = (struct nk_sdl*)ctx->userdata.ptr;\n    NK_ASSERT(sdl);\n\n#ifdef NK_INCLUDE_FONT_BAKING\n    if (sdl->atlas.font_num > 0)\n        nk_font_atlas_clear(&sdl->atlas);\n#endif\n\n    nk_buffer_free(&sdl->ogl.cmds);\n\n    if (sdl->ogl.font_tex != NULL) {\n        SDL_DestroyTexture(sdl->ogl.font_tex);\n        sdl->ogl.font_tex = NULL;\n    }\n\n    nk_free(ctx);\n    sdl->allocator.free(sdl->allocator.userdata, sdl->debug_font);\n    sdl->allocator.free(sdl->allocator.userdata, sdl);\n}\n\n/* Debug Font Width/Height of internal texture atlas\n * This is a result of: ceil(sqrt('~' - ' '))\n * There is a sanity check for this value in nk_sdl_style_set_debug_font */\n#define NK_SDL_DFWH (10)\n\nNK_INTERN float\nnk_sdl_query_debug_font_width(nk_handle handle, float height,\n                              const char *text, int len)\n{\n    NK_UNUSED(handle);\n    return nk_utf_len(text, len) * height;\n}\n\nNK_INTERN void\nnk_sdl_query_debug_font_glypth(nk_handle handle, float height,\n                               struct nk_user_font_glyph *glyph,\n                               nk_rune codepoint, nk_rune next_codepoint)\n{\n    char ascii;\n    int idx, x, y;\n    NK_UNUSED(next_codepoint);\n    NK_UNUSED(handle);\n\n    /* replace non-ASCII characters with question mark */\n    ascii = (codepoint < (nk_rune)' ' || codepoint > (nk_rune)'~')\n            ? '?' : (char)codepoint;\n    NK_ASSERT(ascii >= ' ' && ascii <= '~');\n\n    idx = (int)(ascii - ' ');\n    x = idx / NK_SDL_DFWH;\n    y = idx % NK_SDL_DFWH;\n    NK_ASSERT(x >= 0 && x < NK_SDL_DFWH);\n    NK_ASSERT(y >= 0 && y < NK_SDL_DFWH);\n\n    glyph->height = height;\n    glyph->width = height;\n    glyph->xadvance = height;\n    glyph->uv[0].x = (float)(x + 0) / NK_SDL_DFWH;\n    glyph->uv[0].y = (float)(y + 0) / NK_SDL_DFWH;\n    glyph->uv[1].x = (float)(x + 1) / NK_SDL_DFWH;\n    glyph->uv[1].y = (float)(y + 1) / NK_SDL_DFWH;\n    glyph->offset.x = 0.0f;\n    glyph->offset.y = 0.0f;\n}\n\nNK_API void\nnk_sdl_style_set_debug_font(struct nk_context* ctx)\n{\n    struct nk_user_font* font;\n    struct nk_sdl* sdl;\n    SDL_Surface *surface;\n    SDL_Renderer *renderer;\n    char buf[2];\n    int x, y;\n    bool success;\n    NK_ASSERT(ctx);\n\n    sdl = (struct nk_sdl*)ctx->userdata.ptr;\n    NK_ASSERT(sdl);\n\n    if (sdl->debug_font) {\n        sdl->allocator.free(sdl->allocator.userdata, sdl->debug_font);\n        sdl->debug_font = 0;\n    }\n\n    /* sanity check: formal proof of NK_SDL_DFWH value (which is 10) */\n    NK_ASSERT(SDL_ceil(SDL_sqrt('~' - ' ')) == NK_SDL_DFWH);\n\n    /* We use another Software Renderer just to make sure\n     * that we won't mutate any state in the main Renderer. */\n    surface = SDL_CreateSurface(\n            NK_SDL_DFWH * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE,\n            NK_SDL_DFWH * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE,\n            SDL_PIXELFORMAT_RGBA32);\n    NK_ASSERT(surface);\n    renderer = SDL_CreateSoftwareRenderer(surface);\n    NK_ASSERT(renderer);\n    success = SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);\n    NK_ASSERT(success);\n\n    /* SPACE is the first printable ASCII character */\n    NK_MEMCPY(buf, \" \", sizeof(buf));\n    for (x = 0; x < NK_SDL_DFWH; x++)\n    {\n        for (y = 0; y < NK_SDL_DFWH; y++)\n        {\n            success = SDL_RenderDebugText(\n                    renderer,\n                    (float)(x * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE),\n                    (float)(y * SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE),\n                    buf);\n            NK_ASSERT(success);\n            buf[0]++;\n\n            /* TILDE is the last printable ASCII character */\n            if (buf[0] > '~')\n                break;\n        }\n    }\n    success = SDL_RenderPresent(renderer);\n    NK_ASSERT(success);\n\n    font = sdl->allocator.alloc(sdl->allocator.userdata, 0, sizeof(*font));\n    NK_ASSERT(font);\n    font->userdata.ptr = sdl;\n    font->height = SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE;\n    font->width = &nk_sdl_query_debug_font_width;\n    font->query = &nk_sdl_query_debug_font_glypth;\n\n    /* HACK: nk_sdl_device_upload_atlas turns pixels into SDL_Texture\n     *       and sets said Texture into sdl->ogl.font_tex\n     *       then nk_sdl_render expects same Texture at font->texture */\n    nk_sdl_device_upload_atlas(ctx, surface->pixels, surface->w, surface->h);\n    font->texture.ptr = sdl->ogl.font_tex;\n\n    sdl->debug_font = font;\n    nk_style_set_font(ctx, font);\n\n    SDL_DestroyRenderer(renderer);\n    SDL_DestroySurface(surface);\n}\n\n#endif /* NK_SDL3_RENDERER_IMPLEMENTATION_ONCE */\n#endif /* NK_SDL3_RENDERER_IMPLEMENTATION */\n\n"
  },
  {
    "path": "demo/sdl_opengl2/Makefile",
    "content": "# Install\nBIN = demo\n\n# Flags\nCFLAGS += -std=c89 -Wall -Wextra -pedantic -DSDL_DISABLE_IMMINTRIN_H\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\nifeq ($(OS),Windows_NT)\nBIN := $(BIN).exe\nLIBS = -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lm -lGLU32\nelse\n\tUNAME_S := $(shell uname -s)\n\tifeq ($(UNAME_S),Darwin)\n\t\tLIBS = -lSDL2 -framework OpenGL -lm\n\telse\n\t\tLIBS = -lSDL2 -lGL -lm -lGLU\n\tendif\nendif\n\n$(BIN):\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)\n"
  },
  {
    "path": "demo/sdl_opengl2/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <limits.h>\n#include <time.h>\n\n#include <SDL2/SDL.h>\n#include <SDL2/SDL_opengl.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_SDL_GL2_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_sdl_gl2.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nint\nmain(int argc, char *argv[])\n{\n    /* Platform */\n    SDL_Window *win;\n    SDL_GLContext glContext;\n    int win_width, win_height;\n    int running = 1;\n\n    /* GUI */\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    NK_UNUSED(argc);\n    NK_UNUSED(argv);\n\n    /* SDL setup */\n    SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, \"0\");\n    SDL_Init(SDL_INIT_VIDEO);\n    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);\n    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);\n    SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);\n    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);\n    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);\n    win = SDL_CreateWindow(\"Demo\",\n        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,\n        WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI);\n    glContext = SDL_GL_CreateContext(win);\n    SDL_GetWindowSize(win, &win_width, &win_height);\n\n    /* GUI */\n    ctx = nk_sdl_init(win);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {struct nk_font_atlas *atlas;\n    nk_sdl_font_stash_begin(&atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Roboto-Regular.ttf\", 16, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_sdl_font_stash_end();\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &roboto->handle)*/;}\n\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (running)\n    {\n        /* Input */\n        SDL_Event evt;\n        nk_input_begin(ctx);\n        while (SDL_PollEvent(&evt)) {\n            if (evt.type == SDL_QUIT) goto cleanup;\n            nk_sdl_handle_event(&evt);\n        }\n        nk_sdl_handle_grab(); /* optional grabbing behavior */\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        SDL_GetWindowSize(win, &win_width, &win_height);\n        glViewport(0, 0, win_width, win_height);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(bg.r, bg.g, bg.b, bg.a);\n        /* IMPORTANT: `nk_sdl_render` modifies some global OpenGL state\n         * with blending, scissor, face culling, depth test and viewport and\n         * defaults everything back into a default state.\n         * Make sure to either a.) save and restore or b.) reset your own state after\n         * rendering the UI. */\n        nk_sdl_render(NK_ANTI_ALIASING_ON);\n        SDL_GL_SwapWindow(win);\n    }\n\ncleanup:\n    nk_sdl_shutdown();\n    SDL_GL_DeleteContext(glContext);\n    SDL_DestroyWindow(win);\n    SDL_Quit();\n    return 0;\n}\n\n"
  },
  {
    "path": "demo/sdl_opengl2/nuklear_sdl_gl2.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2017 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_SDL_GL2_H_\n#define NK_SDL_GL2_H_\n\n#include <SDL2/SDL.h>\nNK_API struct nk_context*   nk_sdl_init(SDL_Window *win);\nNK_API void                 nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void                 nk_sdl_font_stash_end(void);\nNK_API int                  nk_sdl_handle_event(SDL_Event *evt);\nNK_API void                 nk_sdl_render(enum nk_anti_aliasing);\nNK_API void                 nk_sdl_shutdown(void);\nNK_API void                 nk_sdl_handle_grab(void);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_SDL_GL2_IMPLEMENTATION\n#include <string.h>\n#include <stdlib.h>\n\nstruct nk_sdl_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint font_tex;\n};\n\nstruct nk_sdl_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstatic struct nk_sdl {\n    SDL_Window *win;\n    struct nk_sdl_device ogl;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    Uint64 time_of_last_frame;\n} sdl;\n\nNK_INTERN void\nnk_sdl_device_upload_atlas(const void *image, int width, int height)\n{\n    struct nk_sdl_device *dev = &sdl.ogl;\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nNK_API void\nnk_sdl_render(enum nk_anti_aliasing AA)\n{\n    /* setup global state */\n    struct nk_sdl_device *dev = &sdl.ogl;\n    int width, height;\n    int display_width, display_height;\n    struct nk_vec2 scale;\n\n    Uint64 now = SDL_GetTicks64();\n    sdl.ctx.delta_time_seconds = (float)(now - sdl.time_of_last_frame) / 1000;\n    sdl.time_of_last_frame = now;\n\n    SDL_GetWindowSize(sdl.win, &width, &height);\n    SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height);\n    scale.x = (float)display_width/(float)width;\n    scale.y = (float)display_height/(float)height;\n\n    glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glEnable(GL_BLEND);\n    glEnable(GL_TEXTURE_2D);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n    /* setup viewport/project */\n    glViewport(0,0,(GLsizei)display_width,(GLsizei)display_height);\n    glMatrixMode(GL_PROJECTION);\n    glPushMatrix();\n    glLoadIdentity();\n    glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);\n    glMatrixMode(GL_MODELVIEW);\n    glPushMatrix();\n    glLoadIdentity();\n\n    glEnableClientState(GL_VERTEX_ARRAY);\n    glEnableClientState(GL_TEXTURE_COORD_ARRAY);\n    glEnableClientState(GL_COLOR_ARRAY);\n    {\n        GLsizei vs = sizeof(struct nk_sdl_vertex);\n        size_t vp = offsetof(struct nk_sdl_vertex, position);\n        size_t vt = offsetof(struct nk_sdl_vertex, uv);\n        size_t vc = offsetof(struct nk_sdl_vertex, col);\n\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        const nk_draw_index *offset = NULL;\n        struct nk_buffer vbuf, ebuf;\n\n        /* fill converting configuration */\n        struct nk_convert_config config;\n        static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n            {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)},\n            {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)},\n            {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)},\n            {NK_VERTEX_LAYOUT_END}\n        };\n        memset(&config, 0, sizeof(config));\n        config.vertex_layout = vertex_layout;\n        config.vertex_size = sizeof(struct nk_sdl_vertex);\n        config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);\n        config.tex_null = dev->tex_null;\n        config.circle_segment_count = 22;\n        config.curve_segment_count = 22;\n        config.arc_segment_count = 22;\n        config.global_alpha = 1.0f;\n        config.shape_AA = AA;\n        config.line_AA = AA;\n\n        /* convert shapes into vertexes */\n        nk_buffer_init_default(&vbuf);\n        nk_buffer_init_default(&ebuf);\n        nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n\n        /* setup vertex buffer pointer */\n        {const void *vertices = nk_buffer_memory_const(&vbuf);\n        glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp));\n        glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt));\n        glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));}\n\n        /* iterate over and execute each draw command */\n        offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);\n        nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds)\n        {\n            if (!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor(\n                (GLint)(cmd->clip_rect.x * scale.x),\n                (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),\n                (GLint)(cmd->clip_rect.w * scale.x),\n                (GLint)(cmd->clip_rect.h * scale.y));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(&sdl.ctx);\n        nk_buffer_clear(&dev->cmds);\n        nk_buffer_free(&vbuf);\n        nk_buffer_free(&ebuf);\n    }\n\n    /* default OpenGL state */\n    glDisableClientState(GL_VERTEX_ARRAY);\n    glDisableClientState(GL_TEXTURE_COORD_ARRAY);\n    glDisableClientState(GL_COLOR_ARRAY);\n\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glDisable(GL_SCISSOR_TEST);\n    glDisable(GL_BLEND);\n    glDisable(GL_TEXTURE_2D);\n\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glMatrixMode(GL_MODELVIEW);\n    glPopMatrix();\n    glMatrixMode(GL_PROJECTION);\n    glPopMatrix();\n    glPopAttrib();\n}\n\nstatic void\nnk_sdl_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    const char *text = SDL_GetClipboardText();\n    if (text) {\n        nk_textedit_paste(edit, text, nk_strlen(text));\n        SDL_free((void *)text);\n    }\n    (void)usr;\n}\n\nstatic void\nnk_sdl_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    char *str = 0;\n    (void)usr;\n    if (!len) return;\n    str = (char*)malloc((size_t)len+1);\n    if (!str) return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n    SDL_SetClipboardText(str);\n    free(str);\n}\n\nNK_API struct nk_context*\nnk_sdl_init(SDL_Window *win)\n{\n    sdl.win = win;\n    nk_init_default(&sdl.ctx, 0);\n    sdl.ctx.clip.copy = nk_sdl_clipboard_copy;\n    sdl.ctx.clip.paste = nk_sdl_clipboard_paste;\n    sdl.ctx.clip.userdata = nk_handle_ptr(0);\n    nk_buffer_init_default(&sdl.ogl.cmds);\n    sdl.time_of_last_frame = SDL_GetTicks64();\n    return &sdl.ctx;\n}\n\nNK_API void\nnk_sdl_font_stash_begin(struct nk_font_atlas **atlas)\n{\n    nk_font_atlas_init_default(&sdl.atlas);\n    nk_font_atlas_begin(&sdl.atlas);\n    *atlas = &sdl.atlas;\n}\n\nNK_API void\nnk_sdl_font_stash_end(void)\n{\n    const void *image; int w, h;\n    image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_sdl_device_upload_atlas(image, w, h);\n    nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.tex_null);\n    if (sdl.atlas.default_font)\n        nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);\n}\n\nNK_API void\nnk_sdl_handle_grab(void)\n{\n    struct nk_context *ctx = &sdl.ctx;\n    if (ctx->input.mouse.grab) {\n        SDL_SetRelativeMouseMode(SDL_TRUE);\n    } else if (ctx->input.mouse.ungrab) {\n        /* better support for older SDL by setting mode first; causes an extra mouse motion event */\n        SDL_SetRelativeMouseMode(SDL_FALSE);\n        SDL_WarpMouseInWindow(sdl.win, (int)ctx->input.mouse.prev.x, (int)ctx->input.mouse.prev.y);\n    } else if (ctx->input.mouse.grabbed) {\n        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n    }\n}\n\nNK_API int\nnk_sdl_handle_event(SDL_Event *evt)\n{\n    struct nk_context *ctx = &sdl.ctx;\n    int ctrl_down = SDL_GetModState() & KMOD_CTRL;\n    static int insert_toggle = 0;\n\n    switch(evt->type)\n    {\n        case SDL_KEYUP: /* KEYUP & KEYDOWN share same routine */\n        case SDL_KEYDOWN:\n            {\n                int down = evt->type == SDL_KEYDOWN;\n                switch(evt->key.keysym.sym)\n                {\n                    case SDLK_RSHIFT: /* RSHIFT & LSHIFT share same routine */\n                    case SDLK_LSHIFT:    nk_input_key(ctx, NK_KEY_SHIFT, down); break;\n                    case SDLK_DELETE:    nk_input_key(ctx, NK_KEY_DEL, down); break;\n\n                    case SDLK_KP_ENTER:\n                    case SDLK_RETURN:    nk_input_key(ctx, NK_KEY_ENTER, down); break;\n\n                    case SDLK_TAB:       nk_input_key(ctx, NK_KEY_TAB, down); break;\n                    case SDLK_BACKSPACE: nk_input_key(ctx, NK_KEY_BACKSPACE, down); break;\n                    case SDLK_HOME:      nk_input_key(ctx, NK_KEY_TEXT_START, down);\n                                         nk_input_key(ctx, NK_KEY_SCROLL_START, down); break;\n                    case SDLK_END:       nk_input_key(ctx, NK_KEY_TEXT_END, down);\n                                         nk_input_key(ctx, NK_KEY_SCROLL_END, down); break;\n                    case SDLK_PAGEDOWN:  nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); break;\n                    case SDLK_PAGEUP:    nk_input_key(ctx, NK_KEY_SCROLL_UP, down); break;\n                    case SDLK_z:         nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && ctrl_down); break;\n                    case SDLK_r:         nk_input_key(ctx, NK_KEY_TEXT_REDO, down && ctrl_down); break;\n                    case SDLK_c:         nk_input_key(ctx, NK_KEY_COPY, down && ctrl_down); break;\n                    case SDLK_v:         nk_input_key(ctx, NK_KEY_PASTE, down && ctrl_down); break;\n                    case SDLK_x:         nk_input_key(ctx, NK_KEY_CUT, down && ctrl_down); break;\n                    case SDLK_b:         nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && ctrl_down); break;\n                    case SDLK_e:         nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && ctrl_down); break;\n                    case SDLK_UP:        nk_input_key(ctx, NK_KEY_UP, down); break;\n                    case SDLK_DOWN:      nk_input_key(ctx, NK_KEY_DOWN, down); break;\n                    case SDLK_ESCAPE:    nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down); break;\n                    case SDLK_INSERT:\n                        if (down) insert_toggle = !insert_toggle;\n                        if (insert_toggle) {\n                            nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);\n                        } else {\n                            nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);\n                        }\n                        break;\n                    case SDLK_a:\n                        if (ctrl_down)\n                            nk_input_key(ctx,NK_KEY_TEXT_SELECT_ALL, down);\n                        break;\n                    case SDLK_LEFT:\n                        if (ctrl_down)\n                            nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);\n                        else nk_input_key(ctx, NK_KEY_LEFT, down);\n                        break;\n                    case SDLK_RIGHT:\n                        if (ctrl_down)\n                            nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n                        else nk_input_key(ctx, NK_KEY_RIGHT, down);\n                        break;\n                }\n            }\n            return 1;\n\n        case SDL_MOUSEBUTTONUP: /* MOUSEBUTTONUP & MOUSEBUTTONDOWN share same routine */\n        case SDL_MOUSEBUTTONDOWN:\n            {\n                int down = evt->type == SDL_MOUSEBUTTONDOWN;\n                const int x = evt->button.x, y = evt->button.y;\n                switch(evt->button.button)\n                {\n                    case SDL_BUTTON_LEFT:\n                        if (evt->button.clicks > 1)\n                            nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);\n                        nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); break;\n                    case SDL_BUTTON_MIDDLE: nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); break;\n                    case SDL_BUTTON_RIGHT:  nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); break;\n                    case SDL_BUTTON_X1:     nk_input_button(ctx, NK_BUTTON_X1, x, y, down); break;\n                    case SDL_BUTTON_X2:     nk_input_button(ctx, NK_BUTTON_X2, x, y, down); break;\n                }\n            }\n            return 1;\n\n        case SDL_MOUSEMOTION:\n            if (ctx->input.mouse.grabbed) {\n                int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;\n                nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);\n            }\n            else nk_input_motion(ctx, evt->motion.x, evt->motion.y);\n            return 1;\n\n        case SDL_TEXTINPUT:\n            {\n                nk_glyph glyph;\n                memcpy(glyph, evt->text.text, NK_UTF_SIZE);\n                nk_input_glyph(ctx, glyph);\n            }\n            return 1;\n\n        case SDL_MOUSEWHEEL:\n            nk_input_scroll(ctx,nk_vec2(evt->wheel.preciseX, evt->wheel.preciseY));\n            return 1;\n    }\n    return 0;\n}\n\nNK_API\nvoid nk_sdl_shutdown(void)\n{\n    struct nk_sdl_device *dev = &sdl.ogl;\n    nk_font_atlas_clear(&sdl.atlas);\n    nk_free(&sdl.ctx);\n    glDeleteTextures(1, &dev->font_tex);\n    nk_buffer_free(&dev->cmds);\n    memset(&sdl, 0, sizeof(sdl));\n}\n\n#endif\n"
  },
  {
    "path": "demo/sdl_opengl3/Makefile",
    "content": "# Install\nBIN = demo\n\n# Flags\nCFLAGS += -g -std=c89 -Wall -Wextra -pedantic -DSDL_DISABLE_IMMINTRIN_H\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\nifeq ($(OS),Windows_NT)\nBIN := $(BIN).exe\nLIBS = -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lm -lGLU32 -lGLEW32\nelse\n\tUNAME_S := $(shell uname -s)\n\tifeq ($(UNAME_S),Darwin)\n\t\tLIBS = -lSDL2 -framework OpenGL -lm -lGLEW\n\telse\n\t\tLIBS = -lSDL2 -lGL -lm -lGLU -lGLEW\n\tendif\nendif\n\n$(BIN):\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)\n"
  },
  {
    "path": "demo/sdl_opengl3/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <limits.h>\n#include <time.h>\n\n#include <GL/glew.h>\n#include <SDL2/SDL.h>\n#include <SDL2/SDL_opengl.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_SDL_GL3_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_sdl_gl3.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define MAX_VERTEX_MEMORY 512 * 1024\n#define MAX_ELEMENT_MEMORY 128 * 1024\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nint main(int argc, char *argv[])\n{\n    /* Platform */\n    SDL_Window *win;\n    SDL_GLContext glContext;\n    int win_width, win_height;\n    int running = 1;\n\n    /* GUI */\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    NK_UNUSED(argc);\n    NK_UNUSED(argv);\n\n    /* SDL setup */\n    SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, \"0\");\n    SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS);\n    SDL_GL_SetAttribute (SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);\n    SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);\n    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);\n    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);\n    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);\n    win = SDL_CreateWindow(\"Demo\",\n        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,\n        WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI);\n    glContext = SDL_GL_CreateContext(win);\n    SDL_GetWindowSize(win, &win_width, &win_height);\n\n    /* OpenGL setup */\n    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);\n    glewExperimental = 1;\n    if (glewInit() != GLEW_OK) {\n        fprintf(stderr, \"Failed to setup GLEW\\n\");\n        exit(1);\n    }\n\n    ctx = nk_sdl_init(win);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {struct nk_font_atlas *atlas;\n    nk_sdl_font_stash_begin(&atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Roboto-Regular.ttf\", 16, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_sdl_font_stash_end();\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &roboto->handle);*/}\n\n    /* style.c */\n    #ifdef INCLUDE_STYLE\n    /* ease regression testing during Nuklear release process; not needed for anything else */\n    #ifdef STYLE_WHITE\n    set_style(ctx, THEME_WHITE);\n    #elif defined(STYLE_RED)\n    set_style(ctx, THEME_RED);\n    #elif defined(STYLE_BLUE)\n    set_style(ctx, THEME_BLUE);\n    #elif defined(STYLE_DARK)\n    set_style(ctx, THEME_DARK);\n    #endif\n    #endif\n\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (running)\n    {\n        /* Input */\n        SDL_Event evt;\n        nk_input_begin(ctx);\n        while (SDL_PollEvent(&evt)) {\n            if (evt.type == SDL_QUIT) goto cleanup;\n            nk_sdl_handle_event(&evt);\n        }\n        nk_sdl_handle_grab(); /* optional grabbing behavior */\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                printf(\"button pressed!\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 22, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        SDL_GetWindowSize(win, &win_width, &win_height);\n        glViewport(0, 0, win_width, win_height);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(bg.r, bg.g, bg.b, bg.a);\n        /* IMPORTANT: `nk_sdl_render` modifies some global OpenGL state\n         * with blending, scissor, face culling, depth test and viewport and\n         * defaults everything back into a default state.\n         * Make sure to either a.) save and restore or b.) reset your own state after\n         * rendering the UI. */\n        nk_sdl_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY);\n        SDL_GL_SwapWindow(win);\n    }\n\ncleanup:\n    nk_sdl_shutdown();\n    SDL_GL_DeleteContext(glContext);\n    SDL_DestroyWindow(win);\n    SDL_Quit();\n    return 0;\n}\n\n"
  },
  {
    "path": "demo/sdl_opengl3/nuklear_sdl_gl3.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_SDL_GL3_H_\n#define NK_SDL_GL3_H_\n\n#include <SDL2/SDL.h>\n#include <SDL2/SDL_opengl.h>\n\nNK_API struct nk_context*   nk_sdl_init(SDL_Window *win);\nNK_API void                 nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void                 nk_sdl_font_stash_end(void);\nNK_API int                  nk_sdl_handle_event(SDL_Event *evt);\nNK_API void                 nk_sdl_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer);\nNK_API void                 nk_sdl_shutdown(void);\nNK_API void                 nk_sdl_device_destroy(void);\nNK_API void                 nk_sdl_device_create(void);\nNK_API void                 nk_sdl_handle_grab(void);\n\n#endif\n\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_SDL_GL3_IMPLEMENTATION\n\n#include <stdlib.h>\n#include <assert.h>\n#include <string.h>\n\nstruct nk_sdl_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint vbo, vao, ebo;\n    GLuint prog;\n    GLuint vert_shdr;\n    GLuint frag_shdr;\n    GLint attrib_pos;\n    GLint attrib_uv;\n    GLint attrib_col;\n    GLint uniform_tex;\n    GLint uniform_proj;\n    GLuint font_tex;\n};\n\nstruct nk_sdl_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstatic struct nk_sdl {\n    SDL_Window *win;\n    struct nk_sdl_device ogl;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    Uint64 time_of_last_frame;\n} sdl;\n\n#ifdef __APPLE__\n  #define NK_SHADER_VERSION \"#version 150\\n\"\n#else\n  #define NK_SHADER_VERSION \"#version 300 es\\n\"\n#endif\nNK_API void\nnk_sdl_device_create(void)\n{\n    GLint status;\n    static const GLchar *vertex_shader =\n        NK_SHADER_VERSION\n        \"uniform mat4 ProjMtx;\\n\"\n        \"in vec2 Position;\\n\"\n        \"in vec2 TexCoord;\\n\"\n        \"in vec4 Color;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main() {\\n\"\n        \"   Frag_UV = TexCoord;\\n\"\n        \"   Frag_Color = Color;\\n\"\n        \"   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\\n\"\n        \"}\\n\";\n    static const GLchar *fragment_shader =\n        NK_SHADER_VERSION\n        \"precision mediump float;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"out vec4 Out_Color;\\n\"\n        \"void main(){\\n\"\n        \"   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    struct nk_sdl_device *dev = &sdl.ogl;\n    nk_buffer_init_default(&dev->cmds);\n    dev->prog = glCreateProgram();\n    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);\n    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);\n    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);\n    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);\n    glCompileShader(dev->vert_shdr);\n    glCompileShader(dev->frag_shdr);\n    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glAttachShader(dev->prog, dev->vert_shdr);\n    glAttachShader(dev->prog, dev->frag_shdr);\n    glLinkProgram(dev->prog);\n    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);\n    assert(status == GL_TRUE);\n\n    dev->uniform_tex = glGetUniformLocation(dev->prog, \"Texture\");\n    dev->uniform_proj = glGetUniformLocation(dev->prog, \"ProjMtx\");\n    dev->attrib_pos = glGetAttribLocation(dev->prog, \"Position\");\n    dev->attrib_uv = glGetAttribLocation(dev->prog, \"TexCoord\");\n    dev->attrib_col = glGetAttribLocation(dev->prog, \"Color\");\n\n    {\n        /* buffer setup */\n        GLsizei vs = sizeof(struct nk_sdl_vertex);\n        size_t vp = offsetof(struct nk_sdl_vertex, position);\n        size_t vt = offsetof(struct nk_sdl_vertex, uv);\n        size_t vc = offsetof(struct nk_sdl_vertex, col);\n\n        glGenBuffers(1, &dev->vbo);\n        glGenBuffers(1, &dev->ebo);\n        glGenVertexArrays(1, &dev->vao);\n\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glEnableVertexAttribArray((GLuint)dev->attrib_pos);\n        glEnableVertexAttribArray((GLuint)dev->attrib_uv);\n        glEnableVertexAttribArray((GLuint)dev->attrib_col);\n\n        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);\n        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);\n        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);\n    }\n\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n}\n\nNK_INTERN void\nnk_sdl_device_upload_atlas(const void *image, int width, int height)\n{\n    struct nk_sdl_device *dev = &sdl.ogl;\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nNK_API void\nnk_sdl_device_destroy(void)\n{\n    struct nk_sdl_device *dev = &sdl.ogl;\n    glDetachShader(dev->prog, dev->vert_shdr);\n    glDetachShader(dev->prog, dev->frag_shdr);\n    glDeleteShader(dev->vert_shdr);\n    glDeleteShader(dev->frag_shdr);\n    glDeleteProgram(dev->prog);\n    glDeleteTextures(1, &dev->font_tex);\n    glDeleteBuffers(1, &dev->vbo);\n    glDeleteBuffers(1, &dev->ebo);\n    nk_buffer_free(&dev->cmds);\n}\n\nNK_API void\nnk_sdl_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)\n{\n    struct nk_sdl_device *dev = &sdl.ogl;\n    int width, height;\n    int display_width, display_height;\n    struct nk_vec2 scale;\n    GLfloat ortho[4][4] = {\n        {  2.0f,  0.0f,  0.0f, 0.0f },\n        {  0.0f, -2.0f,  0.0f, 0.0f },\n        {  0.0f,  0.0f, -1.0f, 0.0f },\n        { -1.0f,  1.0f,  0.0f, 1.0f },\n    };\n\n    Uint64 now = SDL_GetTicks64();\n    sdl.ctx.delta_time_seconds = (float)(now - sdl.time_of_last_frame) / 1000;\n    sdl.time_of_last_frame = now;\n\n    SDL_GetWindowSize(sdl.win, &width, &height);\n    SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height);\n    ortho[0][0] /= (GLfloat)width;\n    ortho[1][1] /= (GLfloat)height;\n\n    scale.x = (float)display_width/(float)width;\n    scale.y = (float)display_height/(float)height;\n\n    /* setup global state */\n    glViewport(0,0,display_width,display_height);\n    glEnable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glActiveTexture(GL_TEXTURE0);\n\n    /* setup program */\n    glUseProgram(dev->prog);\n    glUniform1i(dev->uniform_tex, 0);\n    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        void *vertices, *elements;\n        const nk_draw_index *offset = NULL;\n        struct nk_buffer vbuf, ebuf;\n\n        /* allocate vertex and element buffer */\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);\n\n        /* load vertices/elements directly into vertex/element buffer */\n        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);\n        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n                {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)},\n                {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)},\n                {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)},\n                {NK_VERTEX_LAYOUT_END}\n            };\n            memset(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_sdl_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer);\n            nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer);\n            nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n        }\n        glUnmapBuffer(GL_ARRAY_BUFFER);\n        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);\n\n        /* iterate over and execute each draw command */\n        nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) {\n            if (!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor((GLint)(cmd->clip_rect.x * scale.x),\n                (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),\n                (GLint)(cmd->clip_rect.w * scale.x),\n                (GLint)(cmd->clip_rect.h * scale.y));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(&sdl.ctx);\n        nk_buffer_clear(&dev->cmds);\n    }\n\n    glUseProgram(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n    glDisable(GL_BLEND);\n    glDisable(GL_SCISSOR_TEST);\n}\n\nstatic void\nnk_sdl_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    const char *text = SDL_GetClipboardText();\n    if (text) {\n        nk_textedit_paste(edit, text, nk_strlen(text));\n        SDL_free((void *)text);\n    }\n    (void)usr;\n}\n\nstatic void\nnk_sdl_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    char *str = 0;\n    (void)usr;\n    if (!len) return;\n    str = (char*)malloc((size_t)len+1);\n    if (!str) return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n    SDL_SetClipboardText(str);\n    free(str);\n}\n\nNK_API struct nk_context*\nnk_sdl_init(SDL_Window *win)\n{\n    sdl.win = win;\n    nk_init_default(&sdl.ctx, 0);\n    sdl.ctx.clip.copy = nk_sdl_clipboard_copy;\n    sdl.ctx.clip.paste = nk_sdl_clipboard_paste;\n    sdl.ctx.clip.userdata = nk_handle_ptr(0);\n    nk_sdl_device_create();\n    sdl.time_of_last_frame = SDL_GetTicks64();\n    return &sdl.ctx;\n}\n\nNK_API void\nnk_sdl_font_stash_begin(struct nk_font_atlas **atlas)\n{\n    nk_font_atlas_init_default(&sdl.atlas);\n    nk_font_atlas_begin(&sdl.atlas);\n    *atlas = &sdl.atlas;\n}\n\nNK_API void\nnk_sdl_font_stash_end(void)\n{\n    const void *image; int w, h;\n    image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_sdl_device_upload_atlas(image, w, h);\n    nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.tex_null);\n    if (sdl.atlas.default_font)\n        nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);\n\n}\n\nNK_API void\nnk_sdl_handle_grab(void)\n{\n    struct nk_context *ctx = &sdl.ctx;\n    if (ctx->input.mouse.grab) {\n        SDL_SetRelativeMouseMode(SDL_TRUE);\n    } else if (ctx->input.mouse.ungrab) {\n        /* better support for older SDL by setting mode first; causes an extra mouse motion event */\n        SDL_SetRelativeMouseMode(SDL_FALSE);\n        SDL_WarpMouseInWindow(sdl.win, (int)ctx->input.mouse.prev.x, (int)ctx->input.mouse.prev.y);\n    } else if (ctx->input.mouse.grabbed) {\n        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n    }\n}\n\nNK_API int\nnk_sdl_handle_event(SDL_Event *evt)\n{\n    struct nk_context *ctx = &sdl.ctx;\n    int ctrl_down = SDL_GetModState() & KMOD_CTRL;\n    static int insert_toggle = 0;\n\n    switch(evt->type)\n    {\n        case SDL_KEYUP: /* KEYUP & KEYDOWN share same routine */\n        case SDL_KEYDOWN:\n            {\n                int down = evt->type == SDL_KEYDOWN;\n                switch(evt->key.keysym.sym)\n                {\n                    case SDLK_RSHIFT: /* RSHIFT & LSHIFT share same routine */\n                    case SDLK_LSHIFT:    nk_input_key(ctx, NK_KEY_SHIFT, down); break;\n                    case SDLK_DELETE:    nk_input_key(ctx, NK_KEY_DEL, down); break;\n\n                    case SDLK_KP_ENTER:\n                    case SDLK_RETURN:    nk_input_key(ctx, NK_KEY_ENTER, down); break;\n\n                    case SDLK_TAB:       nk_input_key(ctx, NK_KEY_TAB, down); break;\n                    case SDLK_BACKSPACE: nk_input_key(ctx, NK_KEY_BACKSPACE, down); break;\n                    case SDLK_HOME:      nk_input_key(ctx, NK_KEY_TEXT_START, down);\n                                         nk_input_key(ctx, NK_KEY_SCROLL_START, down); break;\n                    case SDLK_END:       nk_input_key(ctx, NK_KEY_TEXT_END, down);\n                                         nk_input_key(ctx, NK_KEY_SCROLL_END, down); break;\n                    case SDLK_PAGEDOWN:  nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); break;\n                    case SDLK_PAGEUP:    nk_input_key(ctx, NK_KEY_SCROLL_UP, down); break;\n                    case SDLK_z:         nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && ctrl_down); break;\n                    case SDLK_r:         nk_input_key(ctx, NK_KEY_TEXT_REDO, down && ctrl_down); break;\n                    case SDLK_c:         nk_input_key(ctx, NK_KEY_COPY, down && ctrl_down); break;\n                    case SDLK_v:         nk_input_key(ctx, NK_KEY_PASTE, down && ctrl_down); break;\n                    case SDLK_x:         nk_input_key(ctx, NK_KEY_CUT, down && ctrl_down); break;\n                    case SDLK_b:         nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && ctrl_down); break;\n                    case SDLK_e:         nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && ctrl_down); break;\n                    case SDLK_UP:        nk_input_key(ctx, NK_KEY_UP, down); break;\n                    case SDLK_DOWN:      nk_input_key(ctx, NK_KEY_DOWN, down); break;\n\n                    case SDLK_ESCAPE:    nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down); break;\n                    case SDLK_INSERT:\n                        if (down) insert_toggle = !insert_toggle;\n                        if (insert_toggle) {\n                            nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);\n                        } else {\n                            nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);\n                        }\n                        break;\n\n                    case SDLK_a:\n                        if (ctrl_down)\n                            nk_input_key(ctx,NK_KEY_TEXT_SELECT_ALL, down);\n                        break;\n                    case SDLK_LEFT:\n                        if (ctrl_down)\n                            nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);\n                        else nk_input_key(ctx, NK_KEY_LEFT, down);\n                        break;\n                    case SDLK_RIGHT:\n                        if (ctrl_down)\n                            nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n                        else nk_input_key(ctx, NK_KEY_RIGHT, down);\n                        break;\n                }\n            }\n            return 1;\n\n        case SDL_MOUSEBUTTONUP: /* MOUSEBUTTONUP & MOUSEBUTTONDOWN share same routine */\n        case SDL_MOUSEBUTTONDOWN:\n            {\n                int down = evt->type == SDL_MOUSEBUTTONDOWN;\n                const int x = evt->button.x, y = evt->button.y;\n                switch(evt->button.button)\n                {\n                    case SDL_BUTTON_LEFT:\n                        if (evt->button.clicks > 1)\n                            nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);\n                        nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); break;\n                    case SDL_BUTTON_MIDDLE: nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); break;\n                    case SDL_BUTTON_RIGHT:  nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); break;\n                    case SDL_BUTTON_X1:     nk_input_button(ctx, NK_BUTTON_X1, x, y, down); break;\n                    case SDL_BUTTON_X2:     nk_input_button(ctx, NK_BUTTON_X2, x, y, down); break;\n                }\n            }\n            return 1;\n\n        case SDL_MOUSEMOTION:\n            if (ctx->input.mouse.grabbed) {\n                int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;\n                nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);\n            }\n            else nk_input_motion(ctx, evt->motion.x, evt->motion.y);\n            return 1;\n\n        case SDL_TEXTINPUT:\n            {\n                nk_glyph glyph;\n                memcpy(glyph, evt->text.text, NK_UTF_SIZE);\n                nk_input_glyph(ctx, glyph);\n            }\n            return 1;\n\n        case SDL_MOUSEWHEEL:\n            nk_input_scroll(ctx,nk_vec2(evt->wheel.preciseX, evt->wheel.preciseY));\n            return 1;\n    }\n    return 0;\n}\n\nNK_API\nvoid nk_sdl_shutdown(void)\n{\n    nk_font_atlas_clear(&sdl.atlas);\n    nk_free(&sdl.ctx);\n    nk_sdl_device_destroy();\n    memset(&sdl, 0, sizeof(sdl));\n}\n\n#endif\n"
  },
  {
    "path": "demo/sdl_opengles2/Makefile",
    "content": "# Install\nBIN = demo\n\n# Flags\nCFLAGS += -std=c89 -Wall -Wextra -pedantic -DSDL_DISABLE_IMMINTRIN_H\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\nUNAME_S := $(shell uname -s)\nifeq ($(UNAME_S),Darwin)\n\tLIBS = -lSDL2 -framework OpenGLES -lm\nelse\n\tLIBS = -lSDL2 -lGLESv2 -lm\nendif\n\n$(BIN): prepare\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)\n\nweb: prepare\n\temcc $(SRC) -Os -s USE_SDL=2 -o bin/index.html\n\nrpi: prepare\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) `PKG_CONFIG_PATH=/opt/vc/lib/pkgconfig/ pkg-config --cflags --libs bcm_host brcmglesv2` `/usr/local/bin/sdl2-config --libs --cflags`\n\nprepare:\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n"
  },
  {
    "path": "demo/sdl_opengles2/Readme.md",
    "content": "OpenGL ES\n=========\n\nOpenGL ES (OpenGL for Embedded Systems) it is a subset of OpenGL aimed to be simple and fast. It is designed for embedded systems, so for example, this demo could be a good point to start an Android application.\n\n\nLinux, Mac OS X\n---------------\nYou can develop under your favorite modern Linux distro. Most of them support Open GL ES out of the box. But remember that implementation could be different and you have to test your application on the end device too.\n\nJust use `make` to build normal Linux / Mac OS X version.\n\n\nEmscripten\n----------\nSome other demos could be compiled into WebGL too. But the point of this demo is to be compiled without overhead and compatibility mode.\n\n`make web` to build a web-version using Emscripten.\n\n\nRaspberry Pi\n------------\n\nAccelerated Open GL ES2 output supported for Raspberry Pi too. But SDL2 in default Raspbian repositories is not supporting `rpi` video driver by default, so you have to compile SDL2 yourself.\n\nIt is better to compile SDL2 without X11 support (*--disable-video-x11* configure option). Or use `export SDL_VIDEODRIVER=rpi` before each run of the application.\n\nMore info can be found here: https://github.com/vurtun/nuklear/issues/748\n\n`make rpi` to build the demo on your Raspberry Pi board.\n"
  },
  {
    "path": "demo/sdl_opengles2/main.c",
    "content": "/* nuklear - 1.40.8 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <limits.h>\n#include <time.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_SDL_GLES2_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_sdl_gles2.h\"\n\n#define WINDOW_WIDTH 800\n#define WINDOW_HEIGHT 600\n\n#define MAX_VERTEX_MEMORY 512 * 1024\n#define MAX_ELEMENT_MEMORY 128 * 1024\n\n#define UNUSED(a) (void)a\n#define MIN(a,b) ((a) < (b) ? (a) : (b))\n#define MAX(a,b) ((a) < (b) ? (b) : (a))\n#define LEN(a) (sizeof(a)/sizeof(a)[0])\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\n\n\n/* Platform */\nSDL_Window *win;\nint running = nk_true;\n\nstatic void\nMainLoop(void* loopArg){\n    SDL_Event evt;\n    struct nk_context *ctx = (struct nk_context *)loopArg;\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    /* Input */\n    nk_input_begin(ctx);\n    while (SDL_PollEvent(&evt)) {\n        if (evt.type == SDL_QUIT) running = nk_false;\n        nk_sdl_handle_event(&evt);\n    }\n    nk_sdl_handle_grab(); /* optional grabbing behavior */\n    nk_input_end(ctx);\n\n\n    /* GUI */\n    if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 200, 200),\n        NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n        NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n    {\n        nk_menubar_begin(ctx);\n        nk_layout_row_begin(ctx, NK_STATIC, 25, 2);\n        nk_layout_row_push(ctx, 45);\n        if (nk_menu_begin_label(ctx, \"FILE\", NK_TEXT_LEFT, nk_vec2(120, 200))) {\n            nk_layout_row_dynamic(ctx, 30, 1);\n            nk_menu_item_label(ctx, \"OPEN\", NK_TEXT_LEFT);\n            nk_menu_item_label(ctx, \"CLOSE\", NK_TEXT_LEFT);\n            nk_menu_end(ctx);\n        }\n        nk_layout_row_push(ctx, 45);\n        if (nk_menu_begin_label(ctx, \"EDIT\", NK_TEXT_LEFT, nk_vec2(120, 200))) {\n            nk_layout_row_dynamic(ctx, 30, 1);\n            nk_menu_item_label(ctx, \"COPY\", NK_TEXT_LEFT);\n            nk_menu_item_label(ctx, \"CUT\", NK_TEXT_LEFT);\n            nk_menu_item_label(ctx, \"PASTE\", NK_TEXT_LEFT);\n            nk_menu_end(ctx);\n        }\n        nk_layout_row_end(ctx);\n        nk_menubar_end(ctx);\n\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n             nk_layout_row_dynamic(ctx, 30, 2);\n             if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n             if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n             nk_layout_row_dynamic(ctx, 25, 1);\n             nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n        }\n    }\n    nk_end(ctx);\n\n    /* -------------- EXAMPLES ---------------- */\n    #ifdef INCLUDE_CALCULATOR\n      calculator(ctx);\n    #endif\n    #ifdef INCLUDE_CANVAS\n      canvas(ctx);\n    #endif\n    #ifdef INCLUDE_OVERVIEW\n      overview(ctx);\n    #endif\n    #ifdef INCLUDE_CONFIGURATOR\n      style_configurator(ctx, color_table);\n    #endif\n    #ifdef INCLUDE_NODE_EDITOR\n      node_editor(ctx);\n    #endif\n    /* ----------------------------------------- */\n\n    /* Draw */\n    {float bg[4];\n    int win_width, win_height;\n    nk_color_fv(bg, nk_rgb(28,48,62));\n    SDL_GetWindowSize(win, &win_width, &win_height);\n    glViewport(0, 0, win_width, win_height);\n    glClear(GL_COLOR_BUFFER_BIT);\n    glClearColor(bg[0], bg[1], bg[2], bg[3]);\n    /* IMPORTANT: `nk_sdl_render` modifies some global OpenGL state\n     * with blending, scissor, face culling, depth test and viewport and\n     * defaults everything back into a default state.\n     * Make sure to either a.) save and restore or b.) reset your own state after\n     * rendering the UI. */\n    nk_sdl_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_MEMORY, MAX_ELEMENT_MEMORY);\n    SDL_GL_SwapWindow(win);}\n}\n\nint main(int argc, char* argv[])\n{\n    /* GUI */\n    struct nk_context *ctx;\n    SDL_GLContext glContext;\n\n    NK_UNUSED(argc);\n    NK_UNUSED(argv);\n\n    /* SDL setup */\n    SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, \"0\");\n    /*SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS); // - do NOT init SDL on GL ES 2 */\n    SDL_GL_SetAttribute (SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);\n    SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);\n    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);\n    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);\n    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);\n    win = SDL_CreateWindow(\"Demo\",\n        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,\n        WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI);\n    glContext = SDL_GL_CreateContext(win);\n\n    /* OpenGL setup */\n    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);\n\n    ctx = nk_sdl_init(win);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {struct nk_font_atlas *atlas;\n    nk_sdl_font_stash_begin(&atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Roboto-Regular.ttf\", 16, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_sdl_font_stash_end();\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &roboto->handle)*/;}\n\n#if defined(__EMSCRIPTEN__)\n    #include <emscripten.h>\n    emscripten_set_main_loop_arg(MainLoop, (void*)ctx, 0, nk_true);\n#else\n    while (running) MainLoop((void*)ctx);\n#endif\n\n    nk_sdl_shutdown();\n    SDL_GL_DeleteContext(glContext);\n    SDL_DestroyWindow(win);\n    SDL_Quit();\n    return 0;\n}\n\n"
  },
  {
    "path": "demo/sdl_opengles2/nuklear_sdl_gles2.h",
    "content": "/*\n * Nuklear - 1.40.8 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2017 by Micha Mettke\n * emscripten from 2016 by Chris Willcocks\n * OpenGL ES 2.0 from 2017 by Dmitry Hrabrov a.k.a. DeXPeriX\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_SDL_GLES2_H_\n#define NK_SDL_GLES2_H_\n\n#include <SDL2/SDL.h>\n#include <SDL2/SDL_opengles2.h>\n\n\nNK_API struct nk_context*   nk_sdl_init(SDL_Window *win);\nNK_API void                 nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void                 nk_sdl_font_stash_end(void);\nNK_API int                  nk_sdl_handle_event(SDL_Event *evt);\nNK_API void                 nk_sdl_render(enum nk_anti_aliasing , int max_vertex_buffer, int max_element_buffer);\nNK_API void                 nk_sdl_shutdown(void);\nNK_API void                 nk_sdl_device_destroy(void);\nNK_API void                 nk_sdl_device_create(void);\nNK_API void                 nk_sdl_handle_grab(void);\n\n#endif\n\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_SDL_GLES2_IMPLEMENTATION\n#include <stdlib.h>\n#include <assert.h>\n#include <string.h>\n\nstruct nk_sdl_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint vbo, ebo;\n    GLuint prog;\n    GLuint vert_shdr;\n    GLuint frag_shdr;\n    GLint attrib_pos;\n    GLint attrib_uv;\n    GLint attrib_col;\n    GLint uniform_tex;\n    GLint uniform_proj;\n    GLuint font_tex;\n    GLsizei vs;\n    size_t vp, vt, vc;\n};\n\nstruct nk_sdl_vertex {\n    GLfloat position[2];\n    GLfloat uv[2];\n    nk_byte col[4];\n};\n\nstatic struct nk_sdl {\n    SDL_Window *win;\n    struct nk_sdl_device ogl;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    Uint64 time_of_last_frame;\n} sdl;\n\n\n#define NK_SHADER_VERSION \"#version 100\\n\"\n\n\nNK_API void\nnk_sdl_device_create(void)\n{\n    GLint status;\n    static const GLchar *vertex_shader =\n        NK_SHADER_VERSION\n        \"uniform mat4 ProjMtx;\\n\"\n        \"attribute vec2 Position;\\n\"\n        \"attribute vec2 TexCoord;\\n\"\n        \"attribute vec4 Color;\\n\"\n        \"varying vec2 Frag_UV;\\n\"\n        \"varying vec4 Frag_Color;\\n\"\n        \"void main() {\\n\"\n        \"   Frag_UV = TexCoord;\\n\"\n        \"   Frag_Color = Color;\\n\"\n        \"   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\\n\"\n        \"}\\n\";\n    static const GLchar *fragment_shader =\n        NK_SHADER_VERSION\n        \"precision mediump float;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"varying vec2 Frag_UV;\\n\"\n        \"varying vec4 Frag_Color;\\n\"\n        \"void main(){\\n\"\n        \"   gl_FragColor = Frag_Color * texture2D(Texture, Frag_UV);\\n\"\n        \"}\\n\";\n\n    struct nk_sdl_device *dev = &sdl.ogl;\n\n    nk_buffer_init_default(&dev->cmds);\n    dev->prog = glCreateProgram();\n    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);\n    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);\n    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);\n    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);\n    glCompileShader(dev->vert_shdr);\n    glCompileShader(dev->frag_shdr);\n    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glAttachShader(dev->prog, dev->vert_shdr);\n    glAttachShader(dev->prog, dev->frag_shdr);\n    glLinkProgram(dev->prog);\n    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);\n    assert(status == GL_TRUE);\n\n\n    dev->uniform_tex = glGetUniformLocation(dev->prog, \"Texture\");\n    dev->uniform_proj = glGetUniformLocation(dev->prog, \"ProjMtx\");\n    dev->attrib_pos = glGetAttribLocation(dev->prog, \"Position\");\n    dev->attrib_uv = glGetAttribLocation(dev->prog, \"TexCoord\");\n    dev->attrib_col = glGetAttribLocation(dev->prog, \"Color\");\n    {\n        dev->vs = sizeof(struct nk_sdl_vertex);\n        dev->vp = offsetof(struct nk_sdl_vertex, position);\n        dev->vt = offsetof(struct nk_sdl_vertex, uv);\n        dev->vc = offsetof(struct nk_sdl_vertex, col);\n\n        /* Allocate buffers */\n        glGenBuffers(1, &dev->vbo);\n        glGenBuffers(1, &dev->ebo);\n    }\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n}\n\nNK_INTERN void\nnk_sdl_device_upload_atlas(const void *image, int width, int height)\n{\n    struct nk_sdl_device *dev = &sdl.ogl;\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nNK_API void\nnk_sdl_device_destroy(void)\n{\n    struct nk_sdl_device *dev = &sdl.ogl;\n    glDetachShader(dev->prog, dev->vert_shdr);\n    glDetachShader(dev->prog, dev->frag_shdr);\n    glDeleteShader(dev->vert_shdr);\n    glDeleteShader(dev->frag_shdr);\n    glDeleteProgram(dev->prog);\n    glDeleteTextures(1, &dev->font_tex);\n    glDeleteBuffers(1, &dev->vbo);\n    glDeleteBuffers(1, &dev->ebo);\n    nk_buffer_free(&dev->cmds);\n}\n\nNK_API void\nnk_sdl_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)\n{\n    struct nk_sdl_device *dev = &sdl.ogl;\n    int width, height;\n    int display_width, display_height;\n    struct nk_vec2 scale;\n    GLfloat ortho[4][4] = {\n        {  2.0f,  0.0f,  0.0f, 0.0f },\n        {  0.0f, -2.0f,  0.0f, 0.0f },\n        {  0.0f,  0.0f, -1.0f, 0.0f },\n        { -1.0f,  1.0f,  0.0f, 1.0f },\n    };\n\n    Uint64 now = SDL_GetTicks64();\n    sdl.ctx.delta_time_seconds = (float)(now - sdl.time_of_last_frame) / 1000;\n    sdl.time_of_last_frame = now;\n\n    SDL_GetWindowSize(sdl.win, &width, &height);\n    SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height);\n    ortho[0][0] /= (GLfloat)width;\n    ortho[1][1] /= (GLfloat)height;\n\n    scale.x = (float)display_width/(float)width;\n    scale.y = (float)display_height/(float)height;\n\n    /* setup global state */\n    glViewport(0,0,display_width,display_height);\n    glEnable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glActiveTexture(GL_TEXTURE0);\n\n    /* setup program */\n    glUseProgram(dev->prog);\n    glUniform1i(dev->uniform_tex, 0);\n    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        void *vertices, *elements;\n        const nk_draw_index *offset = NULL;\n\n        /* Bind buffers */\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        {\n            /* buffer setup */\n            glEnableVertexAttribArray((GLuint)dev->attrib_pos);\n            glEnableVertexAttribArray((GLuint)dev->attrib_uv);\n            glEnableVertexAttribArray((GLuint)dev->attrib_col);\n\n            glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, dev->vs, (void*)dev->vp);\n            glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, dev->vs, (void*)dev->vt);\n            glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, dev->vs, (void*)dev->vc);\n        }\n\n        glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);\n\n        /* load vertices/elements directly into vertex/element buffer */\n        vertices = malloc((size_t)max_vertex_buffer);\n        elements = malloc((size_t)max_element_buffer);\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n                {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)},\n                {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)},\n                {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)},\n                {NK_VERTEX_LAYOUT_END}\n            };\n            memset(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_sdl_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            {struct nk_buffer vbuf, ebuf;\n            nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer);\n            nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer);\n            nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);}\n        }\n        glBufferSubData(GL_ARRAY_BUFFER, 0, (size_t)max_vertex_buffer, vertices);\n        glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, (size_t)max_element_buffer, elements);\n        free(vertices);\n        free(elements);\n\n        /* iterate over and execute each draw command */\n        nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) {\n            if (!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor((GLint)(cmd->clip_rect.x * scale.x),\n                (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),\n                (GLint)(cmd->clip_rect.w * scale.x),\n                (GLint)(cmd->clip_rect.h * scale.y));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(&sdl.ctx);\n        nk_buffer_clear(&dev->cmds);\n    }\n\n    glUseProgram(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n\n    glDisable(GL_BLEND);\n    glDisable(GL_SCISSOR_TEST);\n}\n\nstatic void\nnk_sdl_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    const char *text = SDL_GetClipboardText();\n    if (text) {\n        nk_textedit_paste(edit, text, nk_strlen(text));\n        SDL_free((void *)text);\n    }\n    (void)usr;\n}\n\nstatic void\nnk_sdl_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    char *str = 0;\n    (void)usr;\n    if (!len) return;\n    str = (char*)malloc((size_t)len+1);\n    if (!str) return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n    SDL_SetClipboardText(str);\n    free(str);\n}\n\nNK_API struct nk_context*\nnk_sdl_init(SDL_Window *win)\n{\n    sdl.win = win;\n    nk_init_default(&sdl.ctx, 0);\n    sdl.ctx.clip.copy = nk_sdl_clipboard_copy;\n    sdl.ctx.clip.paste = nk_sdl_clipboard_paste;\n    sdl.ctx.clip.userdata = nk_handle_ptr(0);\n    nk_sdl_device_create();\n    sdl.time_of_last_frame = SDL_GetTicks64();\n    return &sdl.ctx;\n}\n\nNK_API void\nnk_sdl_font_stash_begin(struct nk_font_atlas **atlas)\n{\n    nk_font_atlas_init_default(&sdl.atlas);\n    nk_font_atlas_begin(&sdl.atlas);\n    *atlas = &sdl.atlas;\n}\n\nNK_API void\nnk_sdl_font_stash_end(void)\n{\n    const void *image; int w, h;\n    image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_sdl_device_upload_atlas(image, w, h);\n    nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.tex_null);\n    if (sdl.atlas.default_font)\n        nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);\n\n}\n\nNK_API void\nnk_sdl_handle_grab(void)\n{\n    struct nk_context *ctx = &sdl.ctx;\n    if (ctx->input.mouse.grab) {\n        SDL_SetRelativeMouseMode(SDL_TRUE);\n    } else if (ctx->input.mouse.ungrab) {\n        /* better support for older SDL by setting mode first; causes an extra mouse motion event */\n        SDL_SetRelativeMouseMode(SDL_FALSE);\n        SDL_WarpMouseInWindow(sdl.win, (int)ctx->input.mouse.prev.x, (int)ctx->input.mouse.prev.y);\n    } else if (ctx->input.mouse.grabbed) {\n        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n    }\n}\n\nNK_API int\nnk_sdl_handle_event(SDL_Event *evt)\n{\n    struct nk_context *ctx = &sdl.ctx;\n    int ctrl_down = SDL_GetModState() & KMOD_CTRL;\n    static int insert_toggle = 0;\n\n    switch(evt->type)\n    {\n        case SDL_KEYUP: /* KEYUP & KEYDOWN share same routine */\n        case SDL_KEYDOWN:\n            {\n                int down = evt->type == SDL_KEYDOWN;\n                switch(evt->key.keysym.sym)\n                {\n                    case SDLK_RSHIFT: /* RSHIFT & LSHIFT share same routine */\n                    case SDLK_LSHIFT:    nk_input_key(ctx, NK_KEY_SHIFT, down); break;\n                    case SDLK_DELETE:    nk_input_key(ctx, NK_KEY_DEL, down); break;\n\n                    case SDLK_KP_ENTER:\n                    case SDLK_RETURN:    nk_input_key(ctx, NK_KEY_ENTER, down); break;\n\n                    case SDLK_TAB:       nk_input_key(ctx, NK_KEY_TAB, down); break;\n                    case SDLK_BACKSPACE: nk_input_key(ctx, NK_KEY_BACKSPACE, down); break;\n                    case SDLK_HOME:      nk_input_key(ctx, NK_KEY_TEXT_START, down);\n                                         nk_input_key(ctx, NK_KEY_SCROLL_START, down); break;\n                    case SDLK_END:       nk_input_key(ctx, NK_KEY_TEXT_END, down);\n                                         nk_input_key(ctx, NK_KEY_SCROLL_END, down); break;\n                    case SDLK_PAGEDOWN:  nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); break;\n                    case SDLK_PAGEUP:    nk_input_key(ctx, NK_KEY_SCROLL_UP, down); break;\n                    case SDLK_z:         nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && ctrl_down); break;\n                    case SDLK_r:         nk_input_key(ctx, NK_KEY_TEXT_REDO, down && ctrl_down); break;\n                    case SDLK_c:         nk_input_key(ctx, NK_KEY_COPY, down && ctrl_down); break;\n                    case SDLK_v:         nk_input_key(ctx, NK_KEY_PASTE, down && ctrl_down); break;\n                    case SDLK_x:         nk_input_key(ctx, NK_KEY_CUT, down && ctrl_down); break;\n                    case SDLK_b:         nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && ctrl_down); break;\n                    case SDLK_e:         nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && ctrl_down); break;\n                    case SDLK_UP:        nk_input_key(ctx, NK_KEY_UP, down); break;\n                    case SDLK_DOWN:      nk_input_key(ctx, NK_KEY_DOWN, down); break;\n                    case SDLK_ESCAPE:    nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down); break;\n                    case SDLK_INSERT:\n                        if (down) insert_toggle = !insert_toggle;\n                        if (insert_toggle) {\n                            nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);\n                        } else {\n                            nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);\n                        }\n                        break;\n                    case SDLK_a:\n                        if (ctrl_down)\n                            nk_input_key(ctx,NK_KEY_TEXT_SELECT_ALL, down);\n                        break;\n                    case SDLK_LEFT:\n                        if (ctrl_down)\n                            nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);\n                        else nk_input_key(ctx, NK_KEY_LEFT, down);\n                        break;\n                    case SDLK_RIGHT:\n                        if (ctrl_down)\n                            nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n                        else nk_input_key(ctx, NK_KEY_RIGHT, down);\n                        break;\n                }\n            }\n            return 1;\n\n        case SDL_MOUSEBUTTONUP: /* MOUSEBUTTONUP & MOUSEBUTTONDOWN share same routine */\n        case SDL_MOUSEBUTTONDOWN:\n            {\n                int down = evt->type == SDL_MOUSEBUTTONDOWN;\n                const int x = evt->button.x, y = evt->button.y;\n                switch(evt->button.button)\n                {\n                    case SDL_BUTTON_LEFT:\n                        if (evt->button.clicks > 1)\n                            nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);\n                        nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); break;\n                    case SDL_BUTTON_MIDDLE: nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); break;\n                    case SDL_BUTTON_RIGHT:  nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); break;\n                    case SDL_BUTTON_X1:     nk_input_button(ctx, NK_BUTTON_X1, x, y, down); break;\n                    case SDL_BUTTON_X2:     nk_input_button(ctx, NK_BUTTON_X2, x, y, down); break;\n                }\n            }\n            return 1;\n\n        case SDL_MOUSEMOTION:\n            if (ctx->input.mouse.grabbed) {\n                int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;\n                nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);\n            }\n            else nk_input_motion(ctx, evt->motion.x, evt->motion.y);\n            return 1;\n\n        case SDL_TEXTINPUT:\n            {\n                nk_glyph glyph;\n                memcpy(glyph, evt->text.text, NK_UTF_SIZE);\n                nk_input_glyph(ctx, glyph);\n            }\n            return 1;\n\n        case SDL_MOUSEWHEEL:\n            nk_input_scroll(ctx,nk_vec2(evt->wheel.preciseX, evt->wheel.preciseY));\n            return 1;\n    }\n    return 0;\n}\n\nNK_API\nvoid nk_sdl_shutdown(void)\n{\n    nk_font_atlas_clear(&sdl.atlas);\n    nk_free(&sdl.ctx);\n    nk_sdl_device_destroy();\n    memset(&sdl, 0, sizeof(sdl));\n}\n\n#endif\n"
  },
  {
    "path": "demo/sdl_renderer/Makefile",
    "content": "# Install\nBIN = demo\n\n# Flags\nCFLAGS += -std=c89 -Wall -Wextra -pedantic -O2 -DSDL_DISABLE_IMMINTRIN_H\nCFLAGS += `sdl2-config --cflags`\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\nifeq ($(OS),Windows_NT)\n#TODO\n#BIN := $(BIN).exe\n#LIBS = -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lm -lGLU32\nelse\n\tUNAME_S := $(shell uname -s)\n\tifeq ($(UNAME_S),Darwin)\n#TODO\t\tLIBS = -lSDL2 -framework OpenGL -lm\n\telse\n\t\tLIBS += -lm -ldl `sdl2-config --libs`\n\tendif\nendif\n\n$(BIN):\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)\n"
  },
  {
    "path": "demo/sdl_renderer/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <limits.h>\n#include <time.h>\n\n#include <SDL2/SDL.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_SDL_RENDERER_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_sdl_renderer.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nint\nmain(void)\n{\n    /* Platform */\n    SDL_Window *win;\n    SDL_Renderer *renderer;\n    int running = 1;\n    int flags = 0;\n    float font_scale = 1;\n\n    /* GUI */\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    /* SDL setup */\n    SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, \"0\");\n    SDL_Init(SDL_INIT_VIDEO);\n\n    win = SDL_CreateWindow(\"Demo\",\n        SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,\n        WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_SHOWN|SDL_WINDOW_ALLOW_HIGHDPI);\n\n    if (win == NULL) {\n        SDL_Log(\"Error SDL_CreateWindow %s\", SDL_GetError());\n        exit(-1);\n    }\n\n    flags |= SDL_RENDERER_ACCELERATED;\n    flags |= SDL_RENDERER_PRESENTVSYNC;\n\n#if 0\n    SDL_SetHint(SDL_HINT_RENDER_BATCHING, \"1\");\n    SDL_SetHint(SDL_HINT_RENDER_DRIVER, \"software\");\n    SDL_SetHint(SDL_HINT_RENDER_DRIVER, \"opengl\");\n    SDL_SetHint(SDL_HINT_RENDER_DRIVER, \"software\");\n    SDL_SetHint(SDL_HINT_RENDER_DRIVER, \"opengles2\");\n#endif\n\n    renderer = SDL_CreateRenderer(win, -1, flags);\n\n    if (renderer == NULL) {\n        SDL_Log(\"Error SDL_CreateRenderer %s\", SDL_GetError());\n        exit(-1);\n    }\n\n    /* scale the renderer output for High-DPI displays */\n    {\n        int render_w, render_h;\n        int window_w, window_h;\n        float scale_x, scale_y;\n        SDL_GetRendererOutputSize(renderer, &render_w, &render_h);\n        SDL_GetWindowSize(win, &window_w, &window_h);\n        scale_x = (float)(render_w) / (float)(window_w);\n        scale_y = (float)(render_h) / (float)(window_h);\n        SDL_RenderSetScale(renderer, scale_x, scale_y);\n        font_scale = scale_y;\n    }\n\n    /* GUI */\n    ctx = nk_sdl_init(win, renderer);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {\n        struct nk_font_atlas *atlas;\n        struct nk_font_config config = nk_font_config(0);\n        struct nk_font *font;\n\n        /* set up the font atlas and add desired font; note that font sizes are\n         * multiplied by font_scale to produce better results at higher DPIs */\n        nk_sdl_font_stash_begin(&atlas);\n        font = nk_font_atlas_add_default(atlas, 13 * font_scale, &config);\n        /*font = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/DroidSans.ttf\", 14 * font_scale, &config);*/\n        /*font = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Roboto-Regular.ttf\", 16 * font_scale, &config);*/\n        /*font = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/kenvector_future_thin.ttf\", 13 * font_scale, &config);*/\n        /*font = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyClean.ttf\", 12 * font_scale, &config);*/\n        /*font = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyTiny.ttf\", 10 * font_scale, &config);*/\n        /*font = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Cousine-Regular.ttf\", 13 * font_scale, &config);*/\n        nk_sdl_font_stash_end();\n\n        /* this hack makes the font appear to be scaled down to the desired\n         * size and is only necessary when font_scale > 1 */\n        font->handle.height /= font_scale;\n        /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n        nk_style_set_font(ctx, &font->handle);\n    }\n\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (running)\n    {\n        /* Input */\n        SDL_Event evt;\n        nk_input_begin(ctx);\n        while (SDL_PollEvent(&evt)) {\n            if (evt.type == SDL_QUIT) goto cleanup;\n            nk_sdl_handle_event(&evt);\n        }\n        nk_sdl_handle_grab(); /* optional grabbing behavior */\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n        canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        SDL_SetRenderDrawColor(renderer, bg.r * 255, bg.g * 255, bg.b * 255, bg.a * 255);\n        SDL_RenderClear(renderer);\n\n        nk_sdl_render(NK_ANTI_ALIASING_ON);\n\n        SDL_RenderPresent(renderer);\n    }\n\ncleanup:\n    nk_sdl_shutdown();\n    SDL_DestroyRenderer(renderer);\n    SDL_DestroyWindow(win);\n    SDL_Quit();\n    return 0;\n}\n"
  },
  {
    "path": "demo/sdl_renderer/nuklear_sdl_renderer.h",
    "content": "/*\n * Nuklear - 4.9.4 - public domain\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_SDL_RENDERER_H_\n#define NK_SDL_RENDERER_H_\n\n#ifndef NK_SDL_RENDERER_SDL_H\n#define NK_SDL_RENDERER_SDL_H <SDL.h>\n#endif\n#include NK_SDL_RENDERER_SDL_H\nNK_API struct nk_context*   nk_sdl_init(SDL_Window *win, SDL_Renderer *renderer);\nNK_API void                 nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void                 nk_sdl_font_stash_end(void);\nNK_API int                  nk_sdl_handle_event(SDL_Event *evt);\nNK_API void                 nk_sdl_render(enum nk_anti_aliasing);\nNK_API void                 nk_sdl_shutdown(void);\nNK_API void                 nk_sdl_handle_grab(void);\n\n#if SDL_COMPILEDVERSION < SDL_VERSIONNUM(2, 0, 22)\n/* Metal API does not support cliprects with negative coordinates or large\n * dimensions. The issue is fixed in SDL2 with version 2.0.22 but until\n * that version is released, the NK_SDL_CLAMP_CLIP_RECT flag can be used to\n * ensure the cliprect is itself clipped to the viewport.\n * See discussion at https://discourse.libsdl.org/t/rendergeometryraw-producing-different-results-in-metal-vs-opengl/34953\n */\n#define NK_SDL_CLAMP_CLIP_RECT\n#endif\n\n#endif /* NK_SDL_RENDERER_H_ */\n\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_SDL_RENDERER_IMPLEMENTATION\n#include <string.h>\n#include <stdlib.h>\n\nstruct nk_sdl_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    SDL_Texture *font_tex;\n};\n\nstruct nk_sdl_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstatic struct nk_sdl {\n    SDL_Window *win;\n    SDL_Renderer *renderer;\n    struct nk_sdl_device ogl;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    Uint64 time_of_last_frame;\n} sdl;\n\nNK_INTERN void\nnk_sdl_device_upload_atlas(const void *image, int width, int height)\n{\n    struct nk_sdl_device *dev = &sdl.ogl;\n\n    SDL_Texture *g_SDLFontTexture = SDL_CreateTexture(sdl.renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height);\n    if (g_SDLFontTexture == NULL) {\n        SDL_Log(\"error creating texture\");\n        return;\n    }\n    SDL_UpdateTexture(g_SDLFontTexture, NULL, image, 4 * width);\n    SDL_SetTextureBlendMode(g_SDLFontTexture, SDL_BLENDMODE_BLEND);\n    dev->font_tex = g_SDLFontTexture;\n}\n\nNK_API void\nnk_sdl_render(enum nk_anti_aliasing AA)\n{\n    /* setup global state */\n    struct nk_sdl_device *dev = &sdl.ogl;\n\n    {\n        SDL_Rect saved_clip;\n#ifdef NK_SDL_CLAMP_CLIP_RECT\n        SDL_Rect viewport;\n#endif\n        SDL_bool clipping_enabled;\n        int vs = sizeof(struct nk_sdl_vertex);\n        size_t vp = offsetof(struct nk_sdl_vertex, position);\n        size_t vt = offsetof(struct nk_sdl_vertex, uv);\n        size_t vc = offsetof(struct nk_sdl_vertex, col);\n\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        const nk_draw_index *offset = NULL;\n        struct nk_buffer vbuf, ebuf;\n\n        /* fill converting configuration */\n        struct nk_convert_config config;\n        static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n            {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, position)},\n            {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sdl_vertex, uv)},\n            {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sdl_vertex, col)},\n            {NK_VERTEX_LAYOUT_END}\n        };\n\n        Uint64 now = SDL_GetTicks64();\n        sdl.ctx.delta_time_seconds = (float)(now - sdl.time_of_last_frame) / 1000;\n        sdl.time_of_last_frame = now;\n\n        NK_MEMSET(&config, 0, sizeof(config));\n        config.vertex_layout = vertex_layout;\n        config.vertex_size = sizeof(struct nk_sdl_vertex);\n        config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);\n        config.tex_null = dev->tex_null;\n        config.circle_segment_count = 22;\n        config.curve_segment_count = 22;\n        config.arc_segment_count = 22;\n        config.global_alpha = 1.0f;\n        config.shape_AA = AA;\n        config.line_AA = AA;\n\n        /* convert shapes into vertexes */\n        nk_buffer_init_default(&vbuf);\n        nk_buffer_init_default(&ebuf);\n        nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n\n        /* iterate over and execute each draw command */\n        offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);\n\n        clipping_enabled = SDL_RenderIsClipEnabled(sdl.renderer);\n        SDL_RenderGetClipRect(sdl.renderer, &saved_clip);\n#ifdef NK_SDL_CLAMP_CLIP_RECT\n        SDL_RenderGetViewport(sdl.renderer, &viewport);\n#endif\n\n        nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds)\n        {\n            if (!cmd->elem_count) continue;\n\n            {\n                SDL_Rect r;\n                r.x = cmd->clip_rect.x;\n                r.y = cmd->clip_rect.y;\n                r.w = cmd->clip_rect.w;\n                r.h = cmd->clip_rect.h;\n#ifdef NK_SDL_CLAMP_CLIP_RECT\n                if (r.x < 0) {\n                    r.w += r.x;\n                    r.x = 0;\n                }\n                if (r.y < 0) {\n                    r.h += r.y;\n                    r.y = 0;\n                }\n                if (r.h > viewport.h) {\n                    r.h = viewport.h;\n                }\n                if (r.w > viewport.w) {\n                    r.w = viewport.w;\n                }\n#endif\n                SDL_RenderSetClipRect(sdl.renderer, &r);\n            }\n\n            {\n                const void *vertices = nk_buffer_memory_const(&vbuf);\n\n                SDL_RenderGeometryRaw(sdl.renderer,\n                        (SDL_Texture *)cmd->texture.ptr,\n                        (const float*)((const nk_byte*)vertices + vp), vs,\n                        (const SDL_Color*)((const nk_byte*)vertices + vc), vs,\n                        (const float*)((const nk_byte*)vertices + vt), vs,\n                        (vbuf.needed / vs),\n                        (void *) offset, cmd->elem_count, 2);\n\n                offset += cmd->elem_count;\n            }\n        }\n\n        SDL_RenderSetClipRect(sdl.renderer, &saved_clip);\n        if (!clipping_enabled) {\n            SDL_RenderSetClipRect(sdl.renderer, NULL);\n        }\n\n        nk_clear(&sdl.ctx);\n        nk_buffer_clear(&dev->cmds);\n        nk_buffer_free(&vbuf);\n        nk_buffer_free(&ebuf);\n    }\n}\n\nstatic void\nnk_sdl_clipboard_paste(nk_handle usr, struct nk_text_edit *edit)\n{\n    const char *text = SDL_GetClipboardText();\n    if (text) {\n        nk_textedit_paste(edit, text, nk_strlen(text));\n        SDL_free((void *)text);\n    }\n    (void)usr;\n}\n\nstatic void\nnk_sdl_clipboard_copy(nk_handle usr, const char *text, int len)\n{\n    char *str = 0;\n    (void)usr;\n    if (!len) return;\n    str = (char*)malloc((size_t)len+1);\n    if (!str) return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n    SDL_SetClipboardText(str);\n    free(str);\n}\n\nNK_API struct nk_context*\nnk_sdl_init(SDL_Window *win, SDL_Renderer *renderer)\n{\n#ifndef NK_SDL_CLAMP_CLIP_RECT\n    SDL_RendererInfo info;\n    SDL_version runtimeVer;\n\n    /* warn for cases where NK_SDL_CLAMP_CLIP_RECT should have been set but isn't */\n    SDL_GetRendererInfo(renderer, &info);\n    SDL_GetVersion(&runtimeVer);\n    if (strncmp(\"metal\", info.name, 5) == 0 &&\n        SDL_VERSIONNUM(runtimeVer.major, runtimeVer.minor, runtimeVer.patch) < SDL_VERSIONNUM(2, 0, 22))\n    {\n        SDL_LogWarn(\n            SDL_LOG_CATEGORY_APPLICATION,\n            \"renderer is using Metal API but runtime SDL version %d.%d.%d is older than compiled version %d.%d.%d, \"\n            \"which may cause issues with rendering\",\n            runtimeVer.major, runtimeVer.minor, runtimeVer.patch,\n            SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL\n        );\n    }\n#endif\n    sdl.win = win;\n    sdl.renderer = renderer;\n    sdl.time_of_last_frame = SDL_GetTicks64();\n    nk_init_default(&sdl.ctx, 0);\n    sdl.ctx.clip.copy = nk_sdl_clipboard_copy;\n    sdl.ctx.clip.paste = nk_sdl_clipboard_paste;\n    sdl.ctx.clip.userdata = nk_handle_ptr(0);\n    nk_buffer_init_default(&sdl.ogl.cmds);\n    return &sdl.ctx;\n}\n\nNK_API void\nnk_sdl_font_stash_begin(struct nk_font_atlas **atlas)\n{\n    nk_font_atlas_init_default(&sdl.atlas);\n    nk_font_atlas_begin(&sdl.atlas);\n    *atlas = &sdl.atlas;\n}\n\nNK_API void\nnk_sdl_font_stash_end(void)\n{\n    const void *image; int w, h;\n    image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_sdl_device_upload_atlas(image, w, h);\n    nk_font_atlas_end(&sdl.atlas, nk_handle_ptr(sdl.ogl.font_tex), &sdl.ogl.tex_null);\n    if (sdl.atlas.default_font)\n        nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);\n}\n\nNK_API void\nnk_sdl_handle_grab(void)\n{\n    struct nk_context *ctx = &sdl.ctx;\n    if (ctx->input.mouse.grab) {\n        SDL_SetRelativeMouseMode(SDL_TRUE);\n    } else if (ctx->input.mouse.ungrab) {\n        /* better support for older SDL by setting mode first; causes an extra mouse motion event */\n        SDL_SetRelativeMouseMode(SDL_FALSE);\n        SDL_WarpMouseInWindow(sdl.win, (int)ctx->input.mouse.prev.x, (int)ctx->input.mouse.prev.y);\n    } else if (ctx->input.mouse.grabbed) {\n        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n    }\n}\n\nNK_API int\nnk_sdl_handle_event(SDL_Event *evt)\n{\n    struct nk_context *ctx = &sdl.ctx;\n    int ctrl_down = SDL_GetModState() & KMOD_CTRL;\n    static int insert_toggle = 0;\n\n    switch(evt->type)\n    {\n        case SDL_KEYUP: /* KEYUP & KEYDOWN share same routine */\n        case SDL_KEYDOWN:\n            {\n                int down = evt->type == SDL_KEYDOWN;\n                switch(evt->key.keysym.sym)\n                {\n                    case SDLK_RSHIFT: /* RSHIFT & LSHIFT share same routine */\n                    case SDLK_LSHIFT:    nk_input_key(ctx, NK_KEY_SHIFT, down); break;\n                    case SDLK_DELETE:    nk_input_key(ctx, NK_KEY_DEL, down); break;\n\n                    case SDLK_KP_ENTER:\n                    case SDLK_RETURN:    nk_input_key(ctx, NK_KEY_ENTER, down); break;\n\n                    case SDLK_TAB:       nk_input_key(ctx, NK_KEY_TAB, down); break;\n                    case SDLK_BACKSPACE: nk_input_key(ctx, NK_KEY_BACKSPACE, down); break;\n                    case SDLK_HOME:      nk_input_key(ctx, NK_KEY_TEXT_START, down);\n                                         nk_input_key(ctx, NK_KEY_SCROLL_START, down); break;\n                    case SDLK_END:       nk_input_key(ctx, NK_KEY_TEXT_END, down);\n                                         nk_input_key(ctx, NK_KEY_SCROLL_END, down); break;\n                    case SDLK_PAGEDOWN:  nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down); break;\n                    case SDLK_PAGEUP:    nk_input_key(ctx, NK_KEY_SCROLL_UP, down); break;\n                    case SDLK_z:         nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && ctrl_down); break;\n                    case SDLK_r:         nk_input_key(ctx, NK_KEY_TEXT_REDO, down && ctrl_down); break;\n                    case SDLK_c:         nk_input_key(ctx, NK_KEY_COPY, down && ctrl_down); break;\n                    case SDLK_v:         nk_input_key(ctx, NK_KEY_PASTE, down && ctrl_down); break;\n                    case SDLK_x:         nk_input_key(ctx, NK_KEY_CUT, down && ctrl_down); break;\n                    case SDLK_b:         nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && ctrl_down); break;\n                    case SDLK_e:         nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && ctrl_down); break;\n                    case SDLK_UP:        nk_input_key(ctx, NK_KEY_UP, down); break;\n                    case SDLK_DOWN:      nk_input_key(ctx, NK_KEY_DOWN, down); break;\n                    case SDLK_ESCAPE:    nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down); break;\n                    case SDLK_INSERT:\n                        if (down) insert_toggle = !insert_toggle;\n                        if (insert_toggle) {\n                            nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);\n                        } else {\n                            nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);\n                        }\n                        break;\n                    case SDLK_a:\n                        if (ctrl_down)\n                            nk_input_key(ctx,NK_KEY_TEXT_SELECT_ALL, down);\n                        break;\n                    case SDLK_LEFT:\n                        if (ctrl_down)\n                            nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);\n                        else nk_input_key(ctx, NK_KEY_LEFT, down);\n                        break;\n                    case SDLK_RIGHT:\n                        if (ctrl_down)\n                            nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n                        else nk_input_key(ctx, NK_KEY_RIGHT, down);\n                        break;\n                }\n            }\n            return 1;\n\n        case SDL_MOUSEBUTTONUP: /* MOUSEBUTTONUP & MOUSEBUTTONDOWN share same routine */\n        case SDL_MOUSEBUTTONDOWN:\n            {\n                int down = evt->type == SDL_MOUSEBUTTONDOWN;\n                const int x = evt->button.x, y = evt->button.y;\n                switch(evt->button.button)\n                {\n                    case SDL_BUTTON_LEFT:\n                        if (evt->button.clicks > 1)\n                            nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);\n                        nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down); break;\n                    case SDL_BUTTON_MIDDLE: nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down); break;\n                    case SDL_BUTTON_RIGHT:  nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down); break;\n                    case SDL_BUTTON_X1:     nk_input_button(ctx, NK_BUTTON_X1, x, y, down); break;\n                    case SDL_BUTTON_X2:     nk_input_button(ctx, NK_BUTTON_X2, x, y, down); break;\n                }\n            }\n            return 1;\n\n        case SDL_MOUSEMOTION:\n            if (ctx->input.mouse.grabbed) {\n                int x = (int)ctx->input.mouse.prev.x, y = (int)ctx->input.mouse.prev.y;\n                nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);\n            }\n            else nk_input_motion(ctx, evt->motion.x, evt->motion.y);\n            return 1;\n\n        case SDL_TEXTINPUT:\n            {\n                nk_glyph glyph;\n                memcpy(glyph, evt->text.text, NK_UTF_SIZE);\n                nk_input_glyph(ctx, glyph);\n            }\n            return 1;\n\n        case SDL_MOUSEWHEEL:\n            nk_input_scroll(ctx,nk_vec2(evt->wheel.preciseX, evt->wheel.preciseY));\n            return 1;\n    }\n    return 0;\n}\n\nNK_API\nvoid nk_sdl_shutdown(void)\n{\n    struct nk_sdl_device *dev = &sdl.ogl;\n    nk_font_atlas_clear(&sdl.atlas);\n    nk_free(&sdl.ctx);\n    SDL_DestroyTexture(dev->font_tex);\n    /* glDeleteTextures(1, &dev->font_tex); */\n    nk_buffer_free(&dev->cmds);\n    memset(&sdl, 0, sizeof(sdl));\n}\n\n#endif /* NK_SDL_RENDERER_IMPLEMENTATION */\n"
  },
  {
    "path": "demo/sdl_vulkan/.gitignore",
    "content": "src/nuklearshaders/*.spv\nsrc/nuklear_sdl_vulkan.h\nshaders/*.spv\n"
  },
  {
    "path": "demo/sdl_vulkan/Makefile",
    "content": "# Install\nBIN = demo\n\n# Flags\nCFLAGS += -std=c89 -Wall -Wextra -pedantic -fsanitize=address -O2\nCFLAGS += -DSDL_DISABLE_IMMINTRIN_H\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\nifeq ($(OS),Windows_NT)\nBIN := $(BIN).exe\nLIBS = -lsdl2 -lvulkan -lm\nelse\n\tUNAME_S := $(shell uname -s)\n\tSDL2 := $(shell pkg-config --libs sdl2)\n\tLIBS = $(SDL2) -lvulkan -lm\nendif\n\n\n$(BIN): shaders/demo.vert.spv shaders/demo.frag.spv\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS)\n\nshaders/demo.vert.spv: shaders/demo.vert\n\tglslc --target-env=vulkan shaders/demo.vert -o shaders/demo.vert.spv\n\nshaders/demo.frag.spv: shaders/demo.frag\n\tglslc --target-env=vulkan shaders/demo.frag -o shaders/demo.frag.spv\n"
  },
  {
    "path": "demo/sdl_vulkan/README.md",
    "content": "# nuklear sdl vulkan\n\n## Theory of operation\n\nThe nuklear SDL vulkan integration creates an independent graphics pipeline that will render the nuklear UI to separate render targets.\nThe application is responsible to fully manage these render targets. So it must ensure they are properly sized (and resized when requested).\n\nFurthermore it is assumed that you will have a swap chain in place and the number of nuklear overlay images and number of swap chain images match.\n\nThis is how you can integrate it in your application:\n\n```\n/*\nSetup: overlay_images have been created and their number match with the number\nof the swap_chain_images of your application. The overlay_images in this\nexample have the same format as your swap_chain images (optional)\n*/\n    struct nk_context *ctx = nk_sdl_init(\n        demo.win, demo.device, demo.physical_device, demo.indices.graphics,\n        demo.overlay_image_views, demo.swap_chain_images_len,\n        demo.swap_chain_image_format, 0,\n        MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);\n[...]\n/*\nin your draw loop draw you can then render to the overlay image at\n`image_index`\nyour own application can then wait for the semaphore and produce\nthe swap_chain_image at `image_index`\nthis should simply sample from the overlay_image (see example)\n*/\nnk_semaphore semaphore =\n    nk_sdl_render(demo.graphics_queue, image_index,\n                    demo.image_available, NK_ANTI_ALIASING_ON);\n    if (!render(&demo, &bg, nk_semaphore, image_index)) {\n        fprintf(stderr, \"render failed\\n\");\n        return false;\n    }\n```\n\nYou must call `nk_sdl_resize` whenever the size of the overlay_images resize.\n\n## Using images\n\nImages can be used by providing a VkImageView as an nk_image_ptr to nuklear:\n\n```\nimg = nk_image_ptr(demo.demo_texture_image_view);\n```\n\nNote that they must have SHADER_READ_OPTIMAL layout\n\nIt is currently not possible to specify how they are being sampled. The nuklear SDL vulkan integration uses a fixed sampler that does linear filtering.\n"
  },
  {
    "path": "demo/sdl_vulkan/main.c",
    "content": "/* nuklear - 1.32.0 - public domain */\n#include <limits.h>\n#include <stdbool.h>\n#include <stddef.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <time.h>\n\n#include <SDL2/SDL.h>\n#include <SDL2/SDL_vulkan.h>\n#include <vulkan/vulkan.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_SDL_VULKAN_IMPLEMENTATION\n#define NK_KEYSTATE_BASED_INPUT\n#include \"../../nuklear.h\"\n#include \"nuklear_sdl_vulkan.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define MAX_VERTEX_BUFFER 512 * 1024\n#define MAX_ELEMENT_BUFFER 128 * 1024\n#define MAX_IN_FLIGHT_FRAMES 2\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/* #define INCLUDE_ALL */\n/* #define INCLUDE_STYLE */\n/* #define INCLUDE_CALCULATOR */\n/* #define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/* #define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n#include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n#include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n#include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n#include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n#include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\n\nstatic const char *validation_layer_name = \"VK_LAYER_KHRONOS_validation\";\n\nstruct queue_family_indices {\n    int graphics;\n    int present;\n};\n\nstruct swap_chain_support_details {\n    VkSurfaceCapabilitiesKHR capabilities;\n    VkSurfaceFormatKHR *formats;\n    uint32_t formats_len;\n    VkPresentModeKHR *present_modes;\n    uint32_t present_modes_len;\n};\n\nvoid swap_chain_support_details_free(\n    struct swap_chain_support_details *swap_chain_support) {\n    if (swap_chain_support->formats_len > 0) {\n        free(swap_chain_support->formats);\n        swap_chain_support->formats = NULL;\n    }\n    if (swap_chain_support->present_modes_len > 0) {\n        free(swap_chain_support->present_modes);\n        swap_chain_support->present_modes = NULL;\n    }\n}\n\nstruct vulkan_demo {\n    SDL_Window *win;\n    VkInstance instance;\n    VkDebugUtilsMessengerEXT debug_messenger;\n    VkSurfaceKHR surface;\n    VkPhysicalDevice physical_device;\n    struct queue_family_indices indices;\n    VkDevice device;\n    VkQueue graphics_queue;\n    VkQueue present_queue;\n    VkSampler sampler;\n\n    VkSwapchainKHR swap_chain;\n    VkImage *swap_chain_images;\n    uint32_t swap_chain_images_len;\n    VkImageView *swap_chain_image_views;\n    VkFormat swap_chain_image_format;\n    VkExtent2D swap_chain_image_extent;\n\n    VkImage *overlay_images;\n    VkImageView *overlay_image_views;\n    VkDeviceMemory *overlay_image_memories;\n\n    VkRenderPass render_pass;\n    VkFramebuffer *framebuffers;\n    VkDescriptorSetLayout descriptor_set_layout;\n    VkDescriptorPool descriptor_pool;\n    VkDescriptorSet *descriptor_sets;\n    VkPipelineLayout pipeline_layout;\n    VkPipeline pipeline;\n    VkCommandPool command_pool;\n    VkCommandBuffer *command_buffers;\n    VkSemaphore *image_available;\n    VkSemaphore *render_finished;\n\n    VkImage demo_texture_image;\n    VkImageView demo_texture_image_view;\n    VkDeviceMemory demo_texture_memory;\n\n    VkFence *render_fence;\n    uint32_t current_in_flight_frame;\n};\n\nVKAPI_ATTR VkBool32 VKAPI_CALL\nvulkan_debug_callback(VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,\n                      VkDebugUtilsMessageTypeFlagsEXT message_type,\n                      const VkDebugUtilsMessengerCallbackDataEXT *callback_data,\n                      void *user_data) {\n    (void)message_severity;\n    (void)message_type;\n    (void)user_data;\n    fprintf(stderr, \"validation layer: %s\\n\", callback_data->pMessage);\n\n    return VK_FALSE;\n}\n\nbool check_validation_layer_support() {\n    uint32_t layer_count;\n    bool ret = false;\n    VkResult result;\n    uint32_t i;\n    VkLayerProperties *available_layers = NULL;\n\n    result = vkEnumerateInstanceLayerProperties(&layer_count, NULL);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumerateInstanceLayerProperties failed: %d\\n\",\n                result);\n        return ret;\n    }\n\n    available_layers = malloc(layer_count * sizeof(VkLayerProperties));\n    result = vkEnumerateInstanceLayerProperties(&layer_count, available_layers);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumerateInstanceLayerProperties failed: %d\\n\",\n                result);\n        goto cleanup;\n    }\n\n    printf(\"Available vulkan layers:\\n\");\n    for (i = 0; i < layer_count; i++) {\n        printf(\"  %s\\n\", available_layers[i].layerName);\n        if (strcmp(validation_layer_name, available_layers[i].layerName) == 0) {\n            ret = true;\n            break;\n        }\n    }\ncleanup:\n    free(available_layers);\n    return ret;\n}\n\nVkResult create_debug_utils_messenger_ext(\n    VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo,\n    const VkAllocationCallbacks *pAllocator,\n    VkDebugUtilsMessengerEXT *pDebugMessenger) {\n    PFN_vkCreateDebugUtilsMessengerEXT func =\n        (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(\n            instance, \"vkCreateDebugUtilsMessengerEXT\");\n    if (func != NULL) {\n        return func(instance, pCreateInfo, pAllocator, pDebugMessenger);\n    } else {\n        return VK_ERROR_EXTENSION_NOT_PRESENT;\n    }\n}\n\nbool create_debug_callback(struct vulkan_demo *demo) {\n    VkResult result;\n\n    VkDebugUtilsMessengerCreateInfoEXT create_info;\n    memset(&create_info, 0, sizeof(VkDebugUtilsMessengerCreateInfoEXT));\n    create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;\n    create_info.messageSeverity =\n        VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |\n        VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;\n    create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |\n                              VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT |\n                              VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;\n    create_info.pfnUserCallback = vulkan_debug_callback;\n\n    result = create_debug_utils_messenger_ext(demo->instance, &create_info,\n                                              NULL, &demo->debug_messenger);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"create_debug_utils_messenger_ext failed %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nbool create_instance(struct vulkan_demo *demo) {\n    uint32_t i;\n    uint32_t available_instance_extension_count;\n    VkResult result;\n    VkExtensionProperties *available_instance_extensions = NULL;\n    bool ret = false;\n    VkApplicationInfo app_info;\n    VkInstanceCreateInfo create_info;\n    uint32_t sdl_extension_count;\n    uint32_t enabled_extension_count;\n    const char **enabled_extensions = NULL;\n    bool validation_layers_installed;\n\n    validation_layers_installed = check_validation_layer_support();\n\n    if (!validation_layers_installed) {\n        fprintf(stdout,\n                \"Couldn't find validation layer %s. Continuing without \"\n                \"validation layers.\\n\",\n                validation_layer_name);\n    }\n    result = vkEnumerateInstanceExtensionProperties(\n        NULL, &available_instance_extension_count, NULL);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumerateInstanceExtensionProperties failed %d\\n\",\n                result);\n        return ret;\n    }\n\n    available_instance_extensions = malloc(available_instance_extension_count *\n                                           sizeof(VkExtensionProperties));\n\n    result = vkEnumerateInstanceExtensionProperties(\n        NULL, &available_instance_extension_count,\n        available_instance_extensions);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumerateInstanceExtensionProperties failed %d\\n\",\n                result);\n        goto cleanup;\n    }\n\n    printf(\"available instance extensions:\\n\");\n    for (i = 0; i < available_instance_extension_count; i++) {\n        printf(\"  %s\\n\", available_instance_extensions[i].extensionName);\n    }\n\n    if (SDL_Vulkan_GetInstanceExtensions(demo->win, &sdl_extension_count,\n                                         NULL) != SDL_TRUE) {\n        fprintf(stderr, \"SDL_Vulkan_GetInstanceExtensions failed: %s\\n\",\n                SDL_GetError());\n        goto cleanup;\n    }\n\n    enabled_extension_count =\n        sdl_extension_count + (validation_layers_installed ? 1 : 0);\n\n    enabled_extensions = malloc(enabled_extension_count * sizeof(char *));\n    if (SDL_Vulkan_GetInstanceExtensions(demo->win, &sdl_extension_count,\n                                         enabled_extensions) != SDL_TRUE) {\n        fprintf(stderr, \"SDL_Vulkan_GetInstanceExtensions failed: %s\\n\",\n                SDL_GetError());\n        goto cleanup;\n    }\n\n    if (validation_layers_installed) {\n        enabled_extensions[sdl_extension_count] =\n            VK_EXT_DEBUG_UTILS_EXTENSION_NAME;\n    }\n\n    printf(\"Trying to enable the following instance extensions: \");\n    for (i = 0; i < enabled_extension_count; i++) {\n        if (i > 0) {\n            printf(\", \");\n        }\n        printf(\"%s\\n\", enabled_extensions[i]);\n    }\n    printf(\"\\n\");\n    for (i = 0; i < enabled_extension_count; i++) {\n        int extension_missing = 1;\n        uint32_t j;\n        for (j = 0; j < available_instance_extension_count; j++) {\n            if (strcmp(enabled_extensions[i],\n                       available_instance_extensions[j].extensionName) == 0) {\n                extension_missing = 0;\n                break;\n            }\n        }\n        if (extension_missing) {\n            fprintf(stderr, \"Extension %s is missing\\n\", enabled_extensions[i]);\n            return ret;\n        }\n    }\n\n    memset(&app_info, 0, sizeof(VkApplicationInfo));\n    app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;\n    app_info.pApplicationName = \"Demo\";\n    app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);\n    app_info.pEngineName = \"No Engine\";\n    app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);\n    app_info.apiVersion = VK_API_VERSION_1_0;\n\n    memset(&create_info, 0, sizeof(VkInstanceCreateInfo));\n    create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;\n    create_info.pApplicationInfo = &app_info;\n    create_info.enabledExtensionCount = enabled_extension_count;\n    create_info.ppEnabledExtensionNames = enabled_extensions;\n    if (validation_layers_installed) {\n        create_info.enabledLayerCount = 1;\n        create_info.ppEnabledLayerNames = &validation_layer_name;\n    }\n    result = vkCreateInstance(&create_info, NULL, &demo->instance);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateInstance result %d\\n\", result);\n        return ret;\n    }\n    if (validation_layers_installed) {\n        ret = create_debug_callback(demo);\n    } else {\n        ret = true;\n    }\ncleanup:\n    if (available_instance_extensions) {\n        free(available_instance_extensions);\n    }\n    if (enabled_extensions) {\n        free(enabled_extensions);\n    }\n\n    return ret;\n}\n\nbool create_surface(struct vulkan_demo *demo) {\n    SDL_bool result;\n    result =\n        SDL_Vulkan_CreateSurface(demo->win, demo->instance, &demo->surface);\n    if (result != SDL_TRUE) {\n        fprintf(stderr, \"creating vulkan surface failed: %s\\n\", SDL_GetError());\n        return false;\n    }\n    return true;\n}\n\nbool find_queue_families(VkPhysicalDevice physical_device, VkSurfaceKHR surface,\n                         struct queue_family_indices *indices) {\n    VkResult result;\n    uint32_t queue_family_count = 0;\n    uint32_t i = 0;\n    bool ret = false;\n    VkQueueFamilyProperties *queue_family_properties;\n    VkBool32 present_support;\n\n    vkGetPhysicalDeviceQueueFamilyProperties(physical_device,\n                                             &queue_family_count, NULL);\n\n    queue_family_properties =\n        malloc(queue_family_count * sizeof(VkQueueFamilyProperties));\n    vkGetPhysicalDeviceQueueFamilyProperties(\n        physical_device, &queue_family_count, queue_family_properties);\n\n    for (i = 0; i < queue_family_count; i++) {\n        if (queue_family_properties[i].queueCount == 0) {\n            continue;\n        }\n        if (queue_family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) {\n            indices->graphics = i;\n        }\n\n        result = vkGetPhysicalDeviceSurfaceSupportKHR(\n            physical_device, i, surface, &present_support);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr,\n                    \"vkGetPhysicalDeviceSurfaceSupportKHR failed with %d\\n\",\n                    result);\n            goto cleanup;\n        }\n        if (present_support == VK_TRUE) {\n            indices->present = i;\n        }\n        if (indices->graphics >= 0 && indices->present >= 0) {\n            break;\n        }\n    }\n    ret = true;\ncleanup:\n    free(queue_family_properties);\n    return ret;\n}\n\nbool query_swap_chain_support(\n    VkPhysicalDevice device, VkSurfaceKHR surface,\n    struct swap_chain_support_details *swap_chain_support) {\n    VkResult result;\n\n    result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(\n        device, surface, &swap_chain_support->capabilities);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr,\n                \"vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed: %d\\n\",\n                result);\n        return false;\n    }\n\n    result = vkGetPhysicalDeviceSurfaceFormatsKHR(\n        device, surface, &swap_chain_support->formats_len, NULL);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkGetPhysicalDeviceSurfaceFormatsKHR failed: %d\\n\",\n                result);\n        return false;\n    }\n\n    if (swap_chain_support->formats_len != 0) {\n        swap_chain_support->formats = malloc(swap_chain_support->formats_len *\n                                             sizeof(VkSurfaceFormatKHR));\n        result = vkGetPhysicalDeviceSurfaceFormatsKHR(\n            device, surface, &swap_chain_support->formats_len,\n            swap_chain_support->formats);\n\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkGetPhysicalDeviceSurfaceFormatsKHR failed: %d\\n\",\n                    result);\n            return false;\n        }\n    }\n\n    result = vkGetPhysicalDeviceSurfacePresentModesKHR(\n        device, surface, &swap_chain_support->present_modes_len, NULL);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr,\n                \"vkGetPhysicalDeviceSurfacePresentModesKHR failed: %d\\n\",\n                result);\n        return false;\n    }\n\n    if (swap_chain_support->present_modes_len != 0) {\n        swap_chain_support->present_modes = malloc(\n            swap_chain_support->present_modes_len * sizeof(VkPresentModeKHR));\n        result = vkGetPhysicalDeviceSurfacePresentModesKHR(\n            device, surface, &swap_chain_support->present_modes_len,\n            swap_chain_support->present_modes);\n\n        if (result != VK_SUCCESS) {\n            fprintf(stderr,\n                    \"vkGetPhysicalDeviceSurfacePresentModesKHR failed: %d\\n\",\n                    result);\n            return false;\n        }\n    }\n\n    return true;\n}\n\nbool is_suitable_physical_device(VkPhysicalDevice physical_device,\n                                 VkSurfaceKHR surface,\n                                 struct queue_family_indices *indices) {\n    VkResult result;\n    uint32_t device_extension_count;\n    uint32_t i;\n    VkExtensionProperties *device_extensions;\n    bool ret = false;\n    struct swap_chain_support_details swap_chain_support;\n    int found_khr_surface = 0;\n\n    VkPhysicalDeviceProperties device_properties;\n    vkGetPhysicalDeviceProperties(physical_device, &device_properties);\n\n    printf(\"Probing physical device %s\\n\", device_properties.deviceName);\n\n    result = vkEnumerateDeviceExtensionProperties(\n        physical_device, NULL, &device_extension_count, NULL);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumerateDeviceExtensionProperties failed: %d\\n\",\n                result);\n        return false;\n    }\n\n    device_extensions =\n        malloc(device_extension_count * sizeof(VkExtensionProperties));\n\n    result = vkEnumerateDeviceExtensionProperties(\n        physical_device, NULL, &device_extension_count, device_extensions);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumerateDeviceExtensionProperties failed: %d\\n\",\n                result);\n        goto cleanup;\n    }\n\n    printf(\"  Supported device extensions:\\n\");\n\n    for (i = 0; i < device_extension_count; i++) {\n        printf(\"    %s\\n\", device_extensions[i].extensionName);\n        if (strcmp(VK_KHR_SWAPCHAIN_EXTENSION_NAME,\n                   device_extensions[i].extensionName) == 0) {\n            found_khr_surface = 1;\n            break;\n        }\n    }\n    if (!found_khr_surface) {\n        printf(\"  Device doesnt support %s\\n\", VK_KHR_SWAPCHAIN_EXTENSION_NAME);\n        goto cleanup;\n    }\n    if (!find_queue_families(physical_device, surface, indices)) {\n        goto cleanup;\n    }\n    if (indices->graphics < 0 || indices->present < 0) {\n        printf(\"  Device is missing graphics and/or present support. graphics: \"\n               \"%d, present: %d\\n\",\n               indices->graphics, indices->present);\n        goto cleanup;\n    }\n\n    if (!query_swap_chain_support(physical_device, surface,\n                                  &swap_chain_support)) {\n        goto cleanup;\n    }\n\n    if (swap_chain_support.formats_len == 0) {\n        printf(\" Device doesn't support any swap chain formats\\n\");\n        goto cleanup;\n    }\n\n    if (swap_chain_support.present_modes_len == 0) {\n        printf(\" Device doesn't support any swap chain present modes\\n\");\n        goto cleanup;\n    }\n    ret = true;\n\ncleanup:\n    free(device_extensions);\n    swap_chain_support_details_free(&swap_chain_support);\n\n    return ret;\n}\n\nbool create_physical_device(struct vulkan_demo *demo) {\n    uint32_t device_count = 0;\n    VkPhysicalDevice *physical_devices;\n    VkResult result;\n    uint32_t i;\n    bool ret = false;\n\n    result = vkEnumeratePhysicalDevices(demo->instance, &device_count, NULL);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumeratePhysicalDevices failed: %d\\n\", result);\n        return ret;\n    }\n    if (device_count == 0) {\n        fprintf(stderr, \"no vulkan capable GPU found!\");\n        return ret;\n    }\n\n    physical_devices = malloc(device_count * sizeof(VkPhysicalDevice));\n    result = vkEnumeratePhysicalDevices(demo->instance, &device_count,\n                                        physical_devices);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEnumeratePhysicalDevices failed: %d\\n\", result);\n        goto cleanup;\n    }\n\n    for (i = 0; i < device_count; i++) {\n        struct queue_family_indices indices = {-1, -1};\n        if (is_suitable_physical_device(physical_devices[i], demo->surface,\n                                        &indices)) {\n            printf(\"  Selecting this device for rendering. Queue families: \"\n                   \"graphics: %d, present: %d!\\n\",\n                   indices.graphics, indices.present);\n            demo->physical_device = physical_devices[i];\n            demo->indices = indices;\n            break;\n        }\n    }\n    if (demo->physical_device == NULL) {\n        fprintf(stderr, \"failed to find a suitable GPU!\\n\");\n    } else {\n        ret = true;\n    }\ncleanup:\n    free(physical_devices);\n    return ret;\n}\n\nbool create_logical_device(struct vulkan_demo *demo) {\n    VkResult result;\n    bool ret = false;\n    float queuePriority = 1.0f;\n    uint32_t num_queues = 1;\n    VkDeviceQueueCreateInfo *queue_create_infos;\n    VkDeviceCreateInfo create_info;\n    const char *swap_chain_extension_name = VK_KHR_SWAPCHAIN_EXTENSION_NAME;\n\n    queue_create_infos = calloc(2, sizeof(VkDeviceQueueCreateInfo));\n    queue_create_infos[0].sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;\n    queue_create_infos[0].queueFamilyIndex = demo->indices.graphics;\n    queue_create_infos[0].queueCount = 1;\n    queue_create_infos[0].pQueuePriorities = &queuePriority;\n\n    if (demo->indices.present != demo->indices.graphics) {\n        queue_create_infos[1].sType =\n            VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;\n        queue_create_infos[1].queueFamilyIndex = demo->indices.present;\n        queue_create_infos[1].queueCount = 1;\n        queue_create_infos[1].pQueuePriorities = &queuePriority;\n        num_queues = 2;\n    }\n\n    memset(&create_info, 0, sizeof(VkDeviceCreateInfo));\n    create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;\n    create_info.queueCreateInfoCount = num_queues;\n    create_info.pQueueCreateInfos = queue_create_infos;\n    create_info.enabledExtensionCount = 1;\n    create_info.ppEnabledExtensionNames = &swap_chain_extension_name;\n\n    result = vkCreateDevice(demo->physical_device, &create_info, NULL,\n                            &demo->device);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateDevice failed: %d\\n\", result);\n        goto cleanup;\n    }\n\n    vkGetDeviceQueue(demo->device, demo->indices.graphics, 0,\n                     &demo->graphics_queue);\n    vkGetDeviceQueue(demo->device, demo->indices.present, 0,\n                     &demo->present_queue);\n    ret = true;\ncleanup:\n    free(queue_create_infos);\n    return ret;\n}\n\nbool create_sampler(struct vulkan_demo *demo) {\n    VkResult result;\n    VkSamplerCreateInfo sampler_info;\n\n    memset(&sampler_info, 0, sizeof(VkSamplerCreateInfo));\n    sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n    sampler_info.pNext = NULL;\n    sampler_info.maxAnisotropy = 1.0;\n    sampler_info.magFilter = VK_FILTER_LINEAR;\n    sampler_info.minFilter = VK_FILTER_LINEAR;\n    sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n    sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.mipLodBias = 0.0f;\n    sampler_info.compareEnable = VK_FALSE;\n    sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;\n    sampler_info.minLod = 0.0f;\n    sampler_info.maxLod = 0.0f;\n    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;\n\n    result = vkCreateSampler(demo->device, &sampler_info, NULL, &demo->sampler);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateSampler failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nVkSurfaceFormatKHR\nchoose_swap_surface_format(VkSurfaceFormatKHR *available_formats,\n                           uint32_t available_formats_len) {\n    VkSurfaceFormatKHR undefined_format = {VK_FORMAT_B8G8R8A8_UNORM,\n                                           VK_COLOR_SPACE_SRGB_NONLINEAR_KHR};\n    uint32_t i;\n    if (available_formats_len == 1 &&\n        available_formats[0].format == VK_FORMAT_UNDEFINED) {\n        return undefined_format;\n    }\n\n    for (i = 0; i < available_formats_len; i++) {\n        if (available_formats[i].format == VK_FORMAT_B8G8R8A8_UNORM &&\n            available_formats[i].colorSpace ==\n                VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) {\n            return available_formats[i];\n        }\n    }\n\n    return available_formats[0];\n}\n\nVkPresentModeKHR\nchoose_swap_present_mode(VkPresentModeKHR *available_present_modes,\n                         uint32_t available_present_modes_len) {\n    uint32_t i;\n    for (i = 0; i < available_present_modes_len; i++) {\n        /*\n        best mode to ensure good input latency while ensuring we are not\n        producing tearing\n        */\n        if (available_present_modes[i] == VK_PRESENT_MODE_MAILBOX_KHR) {\n            return available_present_modes[i];\n        }\n    }\n\n    /* must be supported */\n    return VK_PRESENT_MODE_FIFO_KHR;\n}\n\nVkExtent2D choose_swap_extent(struct vulkan_demo *demo,\n                              VkSurfaceCapabilitiesKHR *capabilities) {\n    int width, height;\n    VkExtent2D actual_extent;\n    if (capabilities->currentExtent.width != 0xFFFFFFFF) {\n        return capabilities->currentExtent;\n    } else {\n        /* not window size! */\n        SDL_Vulkan_GetDrawableSize(demo->win, &width, &height);\n\n        actual_extent.width = (uint32_t)width;\n        actual_extent.height = (uint32_t)height;\n\n        actual_extent.width = NK_MAX(\n            capabilities->minImageExtent.width,\n            NK_MIN(capabilities->maxImageExtent.width, actual_extent.width));\n        actual_extent.height = NK_MAX(\n            capabilities->minImageExtent.height,\n            NK_MIN(capabilities->maxImageExtent.height, actual_extent.height));\n\n        return actual_extent;\n    }\n}\n\nbool create_swap_chain(struct vulkan_demo *demo) {\n    struct swap_chain_support_details swap_chain_support;\n    VkSurfaceFormatKHR surface_format;\n    VkPresentModeKHR present_mode;\n    VkExtent2D extent;\n    VkResult result;\n    VkSwapchainCreateInfoKHR create_info;\n    uint32_t queue_family_indices[2];\n    bool ret = false;\n\n    queue_family_indices[0] = (uint32_t)demo->indices.graphics;\n    queue_family_indices[1] = (uint32_t)demo->indices.present;\n\n    if (!query_swap_chain_support(demo->physical_device, demo->surface,\n                                  &swap_chain_support)) {\n        goto cleanup;\n    }\n    surface_format = choose_swap_surface_format(swap_chain_support.formats,\n                                                swap_chain_support.formats_len);\n    present_mode = choose_swap_present_mode(\n        swap_chain_support.present_modes, swap_chain_support.present_modes_len);\n    extent = choose_swap_extent(demo, &swap_chain_support.capabilities);\n\n    demo->swap_chain_images_len =\n        swap_chain_support.capabilities.minImageCount + 1;\n    if (swap_chain_support.capabilities.maxImageCount > 0 &&\n        demo->swap_chain_images_len >\n            swap_chain_support.capabilities.maxImageCount) {\n        demo->swap_chain_images_len =\n            swap_chain_support.capabilities.maxImageCount;\n    }\n\n    memset(&create_info, 0, sizeof(VkSwapchainCreateInfoKHR));\n    create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;\n    create_info.surface = demo->surface;\n\n    create_info.minImageCount = demo->swap_chain_images_len;\n    create_info.imageFormat = surface_format.format;\n    create_info.imageColorSpace = surface_format.colorSpace;\n    create_info.imageExtent = extent;\n    create_info.imageArrayLayers = 1;\n    create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;\n\n    if (demo->indices.graphics != demo->indices.present) {\n        create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;\n        create_info.queueFamilyIndexCount = 2;\n        create_info.pQueueFamilyIndices = queue_family_indices;\n    } else {\n        create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;\n    }\n\n    create_info.preTransform = swap_chain_support.capabilities.currentTransform;\n        \n    if(swap_chain_support.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR) {\n    \tcreate_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;\n    } else if(swap_chain_support.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR) {\n    \tcreate_info.compositeAlpha = VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR;\n    } else if(swap_chain_support.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR) {\n    \tcreate_info.compositeAlpha = VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR;\n    } else if(swap_chain_support.capabilities.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) {\n    \tcreate_info.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;\n    }\n    \n    create_info.presentMode = present_mode;\n    create_info.clipped = VK_TRUE;\n\n    result = vkCreateSwapchainKHR(demo->device, &create_info, NULL,\n                                  &demo->swap_chain);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateSwapchainKHR failed: %d\\n\", result);\n        goto cleanup;\n    }\n\n    result = vkGetSwapchainImagesKHR(demo->device, demo->swap_chain,\n                                     &demo->swap_chain_images_len, NULL);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkGetSwapchainImagesKHR failed: %d\\n\", result);\n        goto cleanup;\n    }\n    if (demo->swap_chain_images == NULL) {\n        demo->swap_chain_images =\n            malloc(demo->swap_chain_images_len * sizeof(VkImage));\n    }\n    result = vkGetSwapchainImagesKHR(demo->device, demo->swap_chain,\n                                     &demo->swap_chain_images_len,\n                                     demo->swap_chain_images);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkGetSwapchainImagesKHR failed: %d\\n\", result);\n        return false;\n    }\n\n    demo->swap_chain_image_format = surface_format.format;\n    demo->swap_chain_image_extent = extent;\n\n    ret = true;\ncleanup:\n    swap_chain_support_details_free(&swap_chain_support);\n\n    return ret;\n}\n\nbool create_swap_chain_image_views(struct vulkan_demo *demo) {\n    uint32_t i;\n    VkResult result;\n    VkImageViewCreateInfo create_info;\n\n    memset(&create_info, 0, sizeof(VkImageViewCreateInfo));\n    create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n    create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n    create_info.format = demo->swap_chain_image_format;\n    create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;\n    create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;\n    create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;\n    create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;\n    create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    create_info.subresourceRange.baseMipLevel = 0;\n    create_info.subresourceRange.levelCount = 1;\n    create_info.subresourceRange.baseArrayLayer = 0;\n    create_info.subresourceRange.layerCount = 1;\n\n    if (!demo->swap_chain_image_views) {\n        demo->swap_chain_image_views =\n            malloc(demo->swap_chain_images_len * sizeof(VkImageView));\n    }\n\n    for (i = 0; i < demo->swap_chain_images_len; i++) {\n        create_info.image = demo->swap_chain_images[i];\n        result = vkCreateImageView(demo->device, &create_info, NULL,\n                                   &demo->swap_chain_image_views[i]);\n\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateImageView failed: %d\\n\", result);\n            return false;\n        }\n    }\n    return true;\n}\n\nbool create_overlay_images(struct vulkan_demo *demo) {\n    uint32_t i, j;\n    VkResult result;\n    VkMemoryRequirements mem_requirements;\n    VkPhysicalDeviceMemoryProperties mem_properties;\n    int found;\n    VkImageCreateInfo image_info;\n    VkMemoryAllocateInfo alloc_info;\n    VkImageViewCreateInfo image_view_info;\n\n    memset(&image_info, 0, sizeof(VkImageCreateInfo));\n    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n    image_info.imageType = VK_IMAGE_TYPE_2D;\n    image_info.extent.width = demo->swap_chain_image_extent.width;\n    image_info.extent.height = demo->swap_chain_image_extent.height;\n    image_info.extent.depth = 1;\n    image_info.mipLevels = 1;\n    image_info.arrayLayers = 1;\n    image_info.format = demo->swap_chain_image_format;\n    image_info.tiling = VK_IMAGE_TILING_OPTIMAL;\n    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    image_info.usage =\n        VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;\n    image_info.samples = VK_SAMPLE_COUNT_1_BIT;\n    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n\n    memset(&image_view_info, 0, sizeof(VkImageViewCreateInfo));\n    image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n    image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n    image_view_info.format = demo->swap_chain_image_format;\n    image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    image_view_info.subresourceRange.baseMipLevel = 0;\n    image_view_info.subresourceRange.levelCount = 1;\n    image_view_info.subresourceRange.baseArrayLayer = 0;\n    image_view_info.subresourceRange.layerCount = 1;\n\n    if (!demo->overlay_images) {\n        demo->overlay_images =\n            malloc(demo->swap_chain_images_len * sizeof(VkImage));\n    }\n\n    if (!demo->overlay_image_memories) {\n        demo->overlay_image_memories =\n            malloc(demo->swap_chain_images_len * sizeof(VkDeviceMemory));\n    }\n    if (!demo->overlay_image_views) {\n        demo->overlay_image_views =\n            malloc(demo->swap_chain_images_len * sizeof(VkImageView));\n    }\n\n    for (i = 0; i < demo->swap_chain_images_len; i++) {\n        result = vkCreateImage(demo->device, &image_info, NULL,\n                               &demo->overlay_images[i]);\n\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateImage failed for index %lu: %d\\n\",\n                    (unsigned long)i, result);\n            return false;\n        }\n\n        vkGetImageMemoryRequirements(demo->device, demo->overlay_images[i],\n                                     &mem_requirements);\n\n        alloc_info.allocationSize = mem_requirements.size;\n\n        vkGetPhysicalDeviceMemoryProperties(demo->physical_device,\n                                            &mem_properties);\n        found = 0;\n        for (j = 0; j < mem_properties.memoryTypeCount; j++) {\n            if ((mem_requirements.memoryTypeBits & (1 << j)) &&\n                (mem_properties.memoryTypes[j].propertyFlags &\n                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ==\n                    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {\n                found = 1;\n                break;\n            }\n        }\n        if (!found) {\n            fprintf(stderr,\n                    \"failed to find suitable memory type for index %lu!\\n\",\n                    (unsigned long)i);\n            return false;\n        }\n        alloc_info.memoryTypeIndex = j;\n        result = vkAllocateMemory(demo->device, &alloc_info, NULL,\n                                  &demo->overlay_image_memories[i]);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr,\n                    \"failed to allocate vulkan memory for index %lu: %d!\\n\",\n                    (unsigned long)i, result);\n            return false;\n        }\n        result = vkBindImageMemory(demo->device, demo->overlay_images[i],\n                                   demo->overlay_image_memories[i], 0);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"Couldn't bind image memory for index %lu: %d\\n\",\n                    (unsigned long)i, result);\n            return false;\n        }\n\n        image_view_info.image = demo->overlay_images[i];\n        result = vkCreateImageView(demo->device, &image_view_info, NULL,\n                                   &demo->overlay_image_views[i]);\n\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateImageView failed for index %lu: %d\\n\",\n                    (unsigned long)i, result);\n            return false;\n        }\n    }\n    return true;\n}\n\nbool create_render_pass(struct vulkan_demo *demo) {\n    VkAttachmentDescription attachment;\n    VkAttachmentReference color_attachment_ref;\n    VkSubpassDescription subpass;\n    VkSubpassDependency dependency;\n    VkRenderPassCreateInfo render_pass_info;\n    VkResult result;\n\n    memset(&attachment, 0, sizeof(VkAttachmentDescription));\n    attachment.format = demo->swap_chain_image_format;\n    attachment.samples = VK_SAMPLE_COUNT_1_BIT;\n    attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;\n    attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n    attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n    attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n    attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;\n\n    memset(&color_attachment_ref, 0, sizeof(VkAttachmentReference));\n    color_attachment_ref.attachment = 0;\n    color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;\n\n    memset(&subpass, 0, sizeof(VkSubpassDescription));\n    subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;\n    subpass.colorAttachmentCount = 1;\n    subpass.pColorAttachments = &color_attachment_ref;\n\n    memset(&dependency, 0, sizeof(VkSubpassDependency));\n    dependency.srcSubpass = VK_SUBPASS_EXTERNAL;\n    dependency.dstSubpass = 0;\n    dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    dependency.srcAccessMask = 0;\n    dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |\n                               VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n\n    memset(&render_pass_info, 0, sizeof(VkRenderPassCreateInfo));\n    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;\n    render_pass_info.attachmentCount = 1;\n    render_pass_info.pAttachments = &attachment;\n    render_pass_info.subpassCount = 1;\n    render_pass_info.pSubpasses = &subpass;\n    render_pass_info.dependencyCount = 1;\n    render_pass_info.pDependencies = &dependency;\n\n    result = vkCreateRenderPass(demo->device, &render_pass_info, NULL,\n                                &demo->render_pass);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateRenderPass failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nbool create_framebuffers(struct vulkan_demo *demo) {\n    uint32_t i;\n    VkResult result;\n    VkFramebufferCreateInfo framebuffer_info;\n\n    if (!demo->framebuffers) {\n        demo->framebuffers =\n            malloc(demo->swap_chain_images_len * sizeof(VkFramebuffer));\n    }\n\n    memset(&framebuffer_info, 0, sizeof(VkFramebufferCreateInfo));\n    framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;\n    framebuffer_info.renderPass = demo->render_pass;\n    framebuffer_info.attachmentCount = 1;\n    framebuffer_info.width = demo->swap_chain_image_extent.width;\n    framebuffer_info.height = demo->swap_chain_image_extent.height;\n    framebuffer_info.layers = 1;\n\n    for (i = 0; i < demo->swap_chain_images_len; i++) {\n        framebuffer_info.pAttachments = &demo->swap_chain_image_views[i];\n\n        result = vkCreateFramebuffer(demo->device, &framebuffer_info, NULL,\n                                     &demo->framebuffers[i]);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateFramebuffer failed from index %lu: %d\\n\",\n                    (unsigned long)i, result);\n            return false;\n        }\n    }\n    return true;\n}\n\nbool create_descriptor_set_layout(struct vulkan_demo *demo) {\n    VkDescriptorSetLayoutBinding overlay_layout_binding;\n    VkDescriptorSetLayoutCreateInfo descriptor_set_layout_create_nfo;\n    VkResult result;\n\n    memset(&overlay_layout_binding, 0, sizeof(VkDescriptorSetLayoutBinding));\n    overlay_layout_binding.binding = 0;\n    overlay_layout_binding.descriptorCount = 1;\n    overlay_layout_binding.descriptorType =\n        VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    overlay_layout_binding.pImmutableSamplers = NULL;\n    overlay_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;\n\n    memset(&descriptor_set_layout_create_nfo, 0,\n           sizeof(VkDescriptorSetLayoutCreateInfo));\n    descriptor_set_layout_create_nfo.sType =\n        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n    descriptor_set_layout_create_nfo.bindingCount = 1;\n    descriptor_set_layout_create_nfo.pBindings = &overlay_layout_binding;\n\n    result = vkCreateDescriptorSetLayout(demo->device,\n                                         &descriptor_set_layout_create_nfo,\n                                         NULL, &demo->descriptor_set_layout);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateDescriptorSetLayout failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nbool create_descriptor_pool(struct vulkan_demo *demo) {\n    VkDescriptorPoolSize pool_size;\n    VkDescriptorPoolCreateInfo pool_info;\n    VkResult result;\n\n    memset(&pool_size, 0, sizeof(VkDescriptorPoolSize));\n    pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    pool_size.descriptorCount = demo->swap_chain_images_len;\n\n    memset(&pool_info, 0, sizeof(VkDescriptorPoolCreateInfo));\n    pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;\n    pool_info.poolSizeCount = 1;\n    pool_info.pPoolSizes = &pool_size;\n    pool_info.maxSets = demo->swap_chain_images_len;\n    result = vkCreateDescriptorPool(demo->device, &pool_info, NULL,\n                                    &demo->descriptor_pool);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateDescriptorPool failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nvoid update_descriptor_sets(struct vulkan_demo *demo) {\n    uint32_t i;\n    VkDescriptorImageInfo descriptor_image_info;\n    VkWriteDescriptorSet descriptor_write;\n\n    memset(&descriptor_image_info, 0, sizeof(VkDescriptorImageInfo));\n    descriptor_image_info.imageLayout =\n        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n    descriptor_image_info.sampler = demo->sampler;\n\n    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));\n    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n    descriptor_write.dstBinding = 0;\n    descriptor_write.dstArrayElement = 0;\n    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    descriptor_write.descriptorCount = 1;\n    descriptor_write.pImageInfo = &descriptor_image_info;\n\n    for (i = 0; i < demo->swap_chain_images_len; i++) {\n        descriptor_write.dstSet = demo->descriptor_sets[i];\n        descriptor_image_info.imageView = demo->overlay_image_views[i];\n\n        vkUpdateDescriptorSets(demo->device, 1, &descriptor_write, 0, NULL);\n    }\n}\n\nbool create_descriptor_sets(struct vulkan_demo *demo) {\n    bool ret = false;\n    VkDescriptorSetLayout *descriptor_set_layouts;\n    VkDescriptorSetAllocateInfo alloc_info;\n    uint32_t i;\n    VkResult result;\n\n    demo->descriptor_sets =\n        malloc(demo->swap_chain_images_len * sizeof(VkDescriptorSet));\n    descriptor_set_layouts =\n        malloc(demo->swap_chain_images_len * sizeof(VkDescriptorSetLayout));\n\n    for (i = 0; i < demo->swap_chain_images_len; i++) {\n        descriptor_set_layouts[i] = demo->descriptor_set_layout;\n    }\n\n    memset(&alloc_info, 0, sizeof(VkDescriptorSetAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n    alloc_info.descriptorPool = demo->descriptor_pool;\n    alloc_info.descriptorSetCount = demo->swap_chain_images_len;\n    alloc_info.pSetLayouts = descriptor_set_layouts;\n    result = vkAllocateDescriptorSets(demo->device, &alloc_info,\n                                      demo->descriptor_sets);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkAllocateDescriptorSets failed: %d\\n\", result);\n        goto cleanup;\n    }\n\n    update_descriptor_sets(demo);\n\n    ret = true;\ncleanup:\n    free(descriptor_set_layouts);\n\n    return ret;\n}\n\nbool create_shader_module(VkDevice device, char *shader_buffer,\n                          size_t shader_buffer_len,\n                          VkShaderModule *shader_module) {\n    VkShaderModuleCreateInfo create_info;\n    VkResult result;\n\n    memset(&create_info, 0, sizeof(VkShaderModuleCreateInfo));\n    create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;\n    create_info.codeSize = shader_buffer_len;\n    create_info.pCode = (const uint32_t *)shader_buffer;\n\n    result = vkCreateShaderModule(device, &create_info, NULL, shader_module);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateShaderModule failed: %d\\n\", result);\n        return false;\n    }\n\n    return true;\n}\n\nbool create_graphics_pipeline(struct vulkan_demo *demo) {\n    bool ret = false;\n    char *vert_shader_code = NULL;\n    char *frag_shader_code = NULL;\n    VkShaderModule vert_shader_module = VK_NULL_HANDLE;\n    VkShaderModule frag_shader_module = VK_NULL_HANDLE;\n    FILE *fp;\n    size_t file_len;\n    VkPipelineShaderStageCreateInfo vert_shader_stage_info;\n    VkPipelineShaderStageCreateInfo frag_shader_stage_info;\n    VkPipelineShaderStageCreateInfo shader_stages[2];\n    VkPipelineVertexInputStateCreateInfo vertex_input_info;\n    VkPipelineInputAssemblyStateCreateInfo input_assembly;\n    VkViewport viewport;\n    VkRect2D scissor;\n    VkPipelineViewportStateCreateInfo viewport_state;\n    VkPipelineRasterizationStateCreateInfo rasterizer;\n    VkPipelineMultisampleStateCreateInfo multisampling;\n    VkPipelineColorBlendAttachmentState color_blend_attachment;\n    VkPipelineColorBlendStateCreateInfo color_blending;\n    VkPipelineLayoutCreateInfo pipeline_layout_info;\n    VkResult result;\n    VkGraphicsPipelineCreateInfo pipeline_info;\n    size_t read_result;\n\n    fp = fopen(\"shaders/demo.vert.spv\", \"r\");\n    if (!fp) {\n        fprintf(stderr, \"Couldn't open shaders/demo.vert.spv\\n\");\n        return false;\n    }\n    fseek(fp, 0, SEEK_END);\n    file_len = ftell(fp);\n    vert_shader_code = malloc(file_len);\n    fseek(fp, 0, 0);\n    read_result = fread(vert_shader_code, file_len, 1, fp);\n    fclose(fp);\n    if (read_result != 1) {\n        fprintf(stderr, \"Could not read vertex shader\\n\");\n        goto cleanup;\n    }\n\n    if (!create_shader_module(demo->device, vert_shader_code, file_len,\n                              &vert_shader_module)) {\n        goto cleanup;\n    }\n\n    fp = fopen(\"shaders/demo.frag.spv\", \"r\");\n    if (!fp) {\n        fprintf(stderr, \"Couldn't open shaders/demo.frag.spv\\n\");\n        return false;\n    }\n    fseek(fp, 0, SEEK_END);\n    file_len = ftell(fp);\n    frag_shader_code = malloc(file_len);\n    fseek(fp, 0, 0);\n    read_result = fread(frag_shader_code, file_len, 1, fp);\n    fclose(fp);\n    if (read_result != 1) {\n        fprintf(stderr, \"Could not read fragment shader\\n\");\n        goto cleanup;\n    }\n\n    if (!create_shader_module(demo->device, frag_shader_code, file_len,\n                              &frag_shader_module)) {\n        goto cleanup;\n    }\n\n    memset(&vert_shader_stage_info, 0, sizeof(VkPipelineShaderStageCreateInfo));\n    vert_shader_stage_info.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;\n    vert_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;\n    vert_shader_stage_info.module = vert_shader_module;\n    vert_shader_stage_info.pName = \"main\";\n\n    memset(&frag_shader_stage_info, 0, sizeof(VkPipelineShaderStageCreateInfo));\n    frag_shader_stage_info.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;\n    frag_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;\n    frag_shader_stage_info.module = frag_shader_module;\n    frag_shader_stage_info.pName = \"main\";\n\n    shader_stages[0] = vert_shader_stage_info;\n    shader_stages[1] = frag_shader_stage_info;\n\n    memset(&vertex_input_info, 0, sizeof(VkPipelineVertexInputStateCreateInfo));\n    vertex_input_info.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;\n\n    memset(&input_assembly, 0, sizeof(VkPipelineInputAssemblyStateCreateInfo));\n    input_assembly.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;\n    input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;\n    input_assembly.primitiveRestartEnable = VK_FALSE;\n\n    memset(&viewport, 0, sizeof(VkViewport));\n    viewport.x = 0.0f;\n    viewport.y = 0.0f;\n    viewport.width = (float)demo->swap_chain_image_extent.width;\n    viewport.height = (float)demo->swap_chain_image_extent.height;\n    viewport.minDepth = 0.0f;\n    viewport.maxDepth = 1.0f;\n\n    memset(&scissor, 0, sizeof(VkRect2D));\n    scissor.extent.width = demo->swap_chain_image_extent.width;\n    scissor.extent.height = demo->swap_chain_image_extent.height;\n\n    memset(&viewport_state, 0, sizeof(VkPipelineViewportStateCreateInfo));\n    viewport_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;\n    viewport_state.viewportCount = 1;\n    viewport_state.pViewports = &viewport;\n    viewport_state.scissorCount = 1;\n    viewport_state.pScissors = &scissor;\n\n    memset(&rasterizer, 0, sizeof(VkPipelineRasterizationStateCreateInfo));\n    rasterizer.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;\n    rasterizer.depthClampEnable = VK_FALSE;\n    rasterizer.rasterizerDiscardEnable = VK_FALSE;\n    rasterizer.polygonMode = VK_POLYGON_MODE_FILL;\n    rasterizer.lineWidth = 1.0f;\n    rasterizer.cullMode = VK_CULL_MODE_FRONT_BIT;\n    rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;\n    rasterizer.depthBiasEnable = VK_FALSE;\n\n    memset(&multisampling, 0, sizeof(VkPipelineMultisampleStateCreateInfo));\n    multisampling.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;\n    multisampling.sampleShadingEnable = VK_FALSE;\n    multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;\n\n    memset(&color_blend_attachment, 0,\n           sizeof(VkPipelineColorBlendAttachmentState));\n    color_blend_attachment.colorWriteMask =\n        VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |\n        VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;\n    color_blend_attachment.blendEnable = VK_TRUE;\n    color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_ONE;\n    color_blend_attachment.dstColorBlendFactor =\n        VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;\n    color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;\n    color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;\n    color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;\n    color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;\n\n    memset(&color_blending, 0, sizeof(VkPipelineColorBlendStateCreateInfo));\n    color_blending.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;\n    color_blending.logicOpEnable = VK_FALSE;\n    color_blending.logicOp = VK_LOGIC_OP_COPY;\n    color_blending.attachmentCount = 1;\n    color_blending.pAttachments = &color_blend_attachment;\n    color_blending.blendConstants[0] = 1.0f;\n    color_blending.blendConstants[1] = 1.0f;\n    color_blending.blendConstants[2] = 1.0f;\n    color_blending.blendConstants[3] = 1.0f;\n\n    memset(&pipeline_layout_info, 0, sizeof(VkPipelineLayoutCreateInfo));\n    pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;\n    pipeline_layout_info.setLayoutCount = 0;\n    pipeline_layout_info.pushConstantRangeCount = 0;\n    pipeline_layout_info.setLayoutCount = 1;\n    pipeline_layout_info.pSetLayouts = &demo->descriptor_set_layout;\n\n    result = vkCreatePipelineLayout(demo->device, &pipeline_layout_info, NULL,\n                                    &demo->pipeline_layout);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreatePipelineLayout failed: %d\\n\", result);\n        goto cleanup;\n    }\n\n    memset(&pipeline_info, 0, sizeof(VkGraphicsPipelineCreateInfo));\n    pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;\n    pipeline_info.stageCount = 2;\n    pipeline_info.pStages = shader_stages;\n    pipeline_info.pVertexInputState = &vertex_input_info;\n    pipeline_info.pInputAssemblyState = &input_assembly;\n    pipeline_info.pViewportState = &viewport_state;\n    pipeline_info.pRasterizationState = &rasterizer;\n    pipeline_info.pMultisampleState = &multisampling;\n    pipeline_info.pColorBlendState = &color_blending;\n    pipeline_info.layout = demo->pipeline_layout;\n    pipeline_info.renderPass = demo->render_pass;\n    pipeline_info.basePipelineHandle = NULL;\n\n    result = vkCreateGraphicsPipelines(demo->device, NULL, 1, &pipeline_info,\n                                       NULL, &demo->pipeline);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateGraphicsPipelines failed: %d\\n\", result);\n        goto cleanup;\n    }\n    ret = true;\ncleanup:\n    if (frag_shader_module) {\n        vkDestroyShaderModule(demo->device, frag_shader_module, NULL);\n    }\n    if (frag_shader_code) {\n        free(frag_shader_code);\n    }\n    if (vert_shader_module) {\n        vkDestroyShaderModule(demo->device, vert_shader_module, NULL);\n    }\n    if (vert_shader_code) {\n        free(vert_shader_code);\n    }\n\n    return ret;\n}\n\nbool create_command_pool(struct vulkan_demo *demo) {\n    VkCommandPoolCreateInfo pool_info;\n    VkResult result;\n\n    memset(&pool_info, 0, sizeof(VkCommandPoolCreateInfo));\n    pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;\n    pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;\n    pool_info.queueFamilyIndex = demo->indices.graphics;\n\n    result = vkCreateCommandPool(demo->device, &pool_info, NULL,\n                                 &demo->command_pool);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateCommandPool failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nbool create_command_buffers(struct vulkan_demo *demo) {\n    VkCommandBufferAllocateInfo alloc_info;\n    VkResult result;\n\n    demo->command_buffers =\n        malloc(MAX_IN_FLIGHT_FRAMES * sizeof(VkCommandBuffer));\n\n    memset(&alloc_info, 0, sizeof(VkCommandBufferAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;\n    alloc_info.commandPool = demo->command_pool;\n    alloc_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;\n    alloc_info.commandBufferCount = MAX_IN_FLIGHT_FRAMES;\n\n    result = vkAllocateCommandBuffers(demo->device, &alloc_info,\n                                      demo->command_buffers);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkAllocateCommandBuffers failed: %d\\n\", result);\n        return false;\n    }\n\n    return true;\n}\n\nbool create_semaphores(struct vulkan_demo *demo) {\n    VkSemaphoreCreateInfo semaphore_info;\n    VkResult result;\n    uint32_t i;\n    \n    demo->image_available = (VkSemaphore*)malloc(MAX_IN_FLIGHT_FRAMES * sizeof(VkSemaphore));\n    demo->render_finished = (VkSemaphore*)malloc(demo->swap_chain_images_len * sizeof(VkSemaphore));\n    memset(&semaphore_info, 0, sizeof(VkSemaphoreCreateInfo));\n    semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;\n    for(i = 0; i < MAX_IN_FLIGHT_FRAMES; i++) {\n        result = vkCreateSemaphore(demo->device, &semaphore_info, NULL,\n                               &demo->image_available[i]);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateSemaphore failed: %d\\n\", result);\n            return false;\n        }\n    }\n    for(i = 0; i < demo->swap_chain_images_len; i++) {\n        result = vkCreateSemaphore(demo->device, &semaphore_info, NULL,\n                               &demo->render_finished[i]);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateSemaphore failed: %d\\n\", result);\n            return false;\n        }\n    }\n    return true;\n}\n\nbool create_fence(struct vulkan_demo *demo) {\n    VkResult result;\n    VkFenceCreateInfo fence_create_info;\n    uint32_t i;\n    \n    demo->render_fence = (VkFence*)malloc(MAX_IN_FLIGHT_FRAMES * sizeof(VkFence));\n\n    memset(&fence_create_info, 0, sizeof(VkFenceCreateInfo));\n    fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;\n    fence_create_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;\n    \n    for(i = 0; i < MAX_IN_FLIGHT_FRAMES; i++) {\n        result = vkCreateFence(demo->device, &fence_create_info, NULL,\n                           &demo->render_fence[i]);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkCreateFence failed: %d\\n\", result);\n            return false;\n        }\n    }\n    return true;\n}\n\nbool create_swap_chain_related_resources(struct vulkan_demo *demo) {\n    if (!create_swap_chain(demo)) {\n        return false;\n    }\n    if (!create_swap_chain_image_views(demo)) {\n        return false;\n    }\n    if (!create_overlay_images(demo)) {\n        return false;\n    }\n    if (!create_render_pass(demo)) {\n        return false;\n    }\n    if (!create_framebuffers(demo)) {\n        return false;\n    }\n    if (!create_graphics_pipeline(demo)) {\n        return false;\n    }\n    return true;\n}\n\nbool destroy_swap_chain_related_resources(struct vulkan_demo *demo) {\n    uint32_t i;\n    VkResult result;\n\n    result = vkQueueWaitIdle(demo->graphics_queue);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkQueueWaitIdle failed: %d\\n\", result);\n        return false;\n    }\n\n    for (i = 0; i < demo->swap_chain_images_len; i++) {\n        vkDestroyFramebuffer(demo->device, demo->framebuffers[i], NULL);\n        vkDestroyImageView(demo->device, demo->overlay_image_views[i], NULL);\n        vkDestroyImage(demo->device, demo->overlay_images[i], NULL);\n        vkFreeMemory(demo->device, demo->overlay_image_memories[i], NULL);\n        vkDestroyImageView(demo->device, demo->swap_chain_image_views[i], NULL);\n    }\n    vkDestroySwapchainKHR(demo->device, demo->swap_chain, NULL);\n    vkDestroyRenderPass(demo->device, demo->render_pass, NULL);\n    vkDestroyPipeline(demo->device, demo->pipeline, NULL);\n    vkDestroyPipelineLayout(demo->device, demo->pipeline_layout, NULL);\n    return true;\n}\n\nbool create_demo_texture(struct vulkan_demo *demo) {\n    VkResult result;\n    VkMemoryRequirements mem_requirements;\n    VkPhysicalDeviceMemoryProperties mem_properties;\n    int found;\n    uint32_t i;\n    VkImageCreateInfo image_info;\n    VkMemoryAllocateInfo alloc_info;\n    VkImageViewCreateInfo image_view_info;\n    VkBufferCreateInfo buffer_info;\n    struct {\n        VkDeviceMemory memory;\n        VkBuffer buffer;\n    } staging_buffer;\n    void *data;\n    VkCommandBuffer command_buffer;\n    VkCommandBufferBeginInfo begin_info;\n    VkImageMemoryBarrier image_transfer_dst_memory_barrier;\n    VkBufferImageCopy buffer_copy_region;\n    VkImageMemoryBarrier image_shader_memory_barrier;\n    VkFence fence;\n    VkFenceCreateInfo fence_create;\n    VkSubmitInfo submit_info;\n\n    memset(&image_info, 0, sizeof(VkImageCreateInfo));\n    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n    image_info.imageType = VK_IMAGE_TYPE_2D;\n    image_info.extent.width = 2;\n    image_info.extent.height = 2;\n    image_info.extent.depth = 1;\n    image_info.mipLevels = 1;\n    image_info.arrayLayers = 1;\n    image_info.format = VK_FORMAT_R8_UNORM;\n    image_info.tiling = VK_IMAGE_TILING_LINEAR;\n    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    image_info.usage =\n        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;\n    image_info.samples = VK_SAMPLE_COUNT_1_BIT;\n    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n\n    memset(&image_view_info, 0, sizeof(VkImageViewCreateInfo));\n    image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n    image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n    image_view_info.format = VK_FORMAT_R8_UNORM;\n    image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;\n    image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    image_view_info.subresourceRange.baseMipLevel = 0;\n    image_view_info.subresourceRange.levelCount = 1;\n    image_view_info.subresourceRange.baseArrayLayer = 0;\n    image_view_info.subresourceRange.layerCount = 1;\n\n    result = vkCreateImage(demo->device, &image_info, NULL,\n                           &demo->demo_texture_image);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateImage failed: %d\\n\", result);\n        return false;\n    }\n\n    vkGetImageMemoryRequirements(demo->device, demo->demo_texture_image,\n                                 &mem_requirements);\n\n    alloc_info.allocationSize = mem_requirements.size;\n\n    vkGetPhysicalDeviceMemoryProperties(demo->physical_device, &mem_properties);\n    found = 0;\n    for (i = 0; i < mem_properties.memoryTypeCount; i++) {\n        if ((mem_requirements.memoryTypeBits & (1 << i)) &&\n            (mem_properties.memoryTypes[i].propertyFlags &\n             VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) ==\n                VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) {\n            found = 1;\n            break;\n        }\n    }\n    if (!found) {\n        fprintf(stderr, \"failed to find suitable memory for demo texture!\\n\");\n        return false;\n    }\n    alloc_info.memoryTypeIndex = i;\n    result = vkAllocateMemory(demo->device, &alloc_info, NULL,\n                              &demo->demo_texture_memory);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr,\n                \"failed to allocate vulkan memory for demo texture: %d!\\n\",\n                result);\n        return false;\n    }\n    result = vkBindImageMemory(demo->device, demo->demo_texture_image,\n                               demo->demo_texture_memory, 0);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"Couldn't bind image memory for demo texture: %d\\n\",\n                result);\n        return false;\n    }\n\n    image_view_info.image = demo->demo_texture_image;\n    result = vkCreateImageView(demo->device, &image_view_info, NULL,\n                               &demo->demo_texture_image_view);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateImageView failed for demo texture: %d\\n\",\n                result);\n        return false;\n    }\n\n    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));\n    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n    buffer_info.size = alloc_info.allocationSize;\n    buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;\n    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    result = vkCreateBuffer(demo->device, &buffer_info, NULL,\n                            &staging_buffer.buffer);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateBuffer failed for demo texture: %d\\n\", result);\n        return false;\n    }\n    vkGetBufferMemoryRequirements(demo->device, staging_buffer.buffer,\n                                  &mem_requirements);\n\n    alloc_info.allocationSize = mem_requirements.size;\n    found = 0;\n    for (i = 0; i < mem_properties.memoryTypeCount; i++) {\n        if ((mem_requirements.memoryTypeBits & (1 << i)) &&\n            (mem_properties.memoryTypes[i].propertyFlags &\n             (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n              VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) ==\n                (VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n                 VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)) {\n            found = 1;\n            break;\n        }\n    }\n    if (!found) {\n        fprintf(stderr, \"failed to find suitable staging buffer memory for \"\n                        \"demo texture!\\n\");\n        return false;\n    }\n    alloc_info.memoryTypeIndex = i;\n    result = vkAllocateMemory(demo->device, &alloc_info, NULL,\n                              &staging_buffer.memory);\n    if (!found) {\n        fprintf(stderr, \"vkAllocateMemory failed for demo texture: %d\\n\",\n                result);\n        return false;\n    }\n    result = vkBindBufferMemory(demo->device, staging_buffer.buffer,\n                                staging_buffer.memory, 0);\n    if (!found) {\n        fprintf(stderr, \"vkBindBufferMemory failed for demo texture: %d\\n\",\n                result);\n        return false;\n    }\n\n    result = vkMapMemory(demo->device, staging_buffer.memory, 0,\n                         sizeof(uint32_t), 0, &data);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkMapMemory failed for demo texture: %d\\n\", result);\n        return false;\n    }\n    *((uint32_t *)data) = 0x00FFFF00;\n    vkUnmapMemory(demo->device, staging_buffer.memory);\n\n    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));\n    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n    command_buffer = demo->command_buffers[0];\n    result = vkBeginCommandBuffer(command_buffer, &begin_info);\n\n    memset(&image_transfer_dst_memory_barrier, 0, sizeof(VkImageMemoryBarrier));\n    image_transfer_dst_memory_barrier.sType =\n        VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n    image_transfer_dst_memory_barrier.image = demo->demo_texture_image;\n    image_transfer_dst_memory_barrier.srcQueueFamilyIndex =\n        VK_QUEUE_FAMILY_IGNORED;\n    image_transfer_dst_memory_barrier.dstQueueFamilyIndex =\n        VK_QUEUE_FAMILY_IGNORED;\n    image_transfer_dst_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    image_transfer_dst_memory_barrier.newLayout =\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n    image_transfer_dst_memory_barrier.subresourceRange.aspectMask =\n        VK_IMAGE_ASPECT_COLOR_BIT;\n    image_transfer_dst_memory_barrier.subresourceRange.levelCount = 1;\n    image_transfer_dst_memory_barrier.subresourceRange.layerCount = 1;\n    image_transfer_dst_memory_barrier.dstAccessMask =\n        VK_ACCESS_TRANSFER_WRITE_BIT;\n\n    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\n                         VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,\n                         &image_transfer_dst_memory_barrier);\n\n    memset(&buffer_copy_region, 0, sizeof(VkBufferImageCopy));\n    buffer_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    buffer_copy_region.imageSubresource.layerCount = 1;\n    buffer_copy_region.imageExtent.width = 2;\n    buffer_copy_region.imageExtent.height = 2;\n    buffer_copy_region.imageExtent.depth = 1;\n\n    vkCmdCopyBufferToImage(\n        command_buffer, staging_buffer.buffer, demo->demo_texture_image,\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_copy_region);\n\n    memset(&image_shader_memory_barrier, 0, sizeof(VkImageMemoryBarrier));\n    image_shader_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n    image_shader_memory_barrier.image = demo->demo_texture_image;\n    image_shader_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_shader_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_shader_memory_barrier.oldLayout =\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n    image_shader_memory_barrier.newLayout =\n        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n    image_shader_memory_barrier.subresourceRange.aspectMask =\n        VK_IMAGE_ASPECT_COLOR_BIT;\n    image_shader_memory_barrier.subresourceRange.levelCount = 1;\n    image_shader_memory_barrier.subresourceRange.layerCount = 1;\n    image_shader_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,\n    image_shader_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,\n\n    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,\n                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0,\n                         NULL, 1, &image_shader_memory_barrier);\n\n    result = vkEndCommandBuffer(command_buffer);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEndCommandBuffer failed for demo texture: %d\\n\",\n                result);\n        return false;\n    }\n\n    memset(&fence_create, 0, sizeof(VkFenceCreateInfo));\n    fence_create.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;\n    result = vkCreateFence(demo->device, &fence_create, NULL, &fence);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkCreateFence failed for demo texture: %d\\n\", result);\n        return false;\n    }\n\n    memset(&submit_info, 0, sizeof(VkSubmitInfo));\n    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n    submit_info.commandBufferCount = 1;\n    submit_info.pCommandBuffers = &command_buffer;\n\n    result = vkQueueSubmit(demo->graphics_queue, 1, &submit_info, fence);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkQueueSubmit failed for demo texture: %d\\n\", result);\n        return false;\n    }\n    result = vkWaitForFences(demo->device, 1, &fence, VK_TRUE, UINT64_MAX);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkWaitForFences failed for demo texture: %d\\n\",\n                result);\n        return false;\n    }\n\n    vkDestroyBuffer(demo->device, staging_buffer.buffer, NULL);\n    vkFreeMemory(demo->device, staging_buffer.memory, NULL);\n    vkDestroyFence(demo->device, fence, NULL);\n\n    return true;\n}\n\nbool create_vulkan_demo(struct vulkan_demo *demo) {\n    if (!create_instance(demo)) {\n        return false;\n    }\n    if (!create_surface(demo)) {\n        return false;\n    }\n    if (!create_physical_device(demo)) {\n        return false;\n    }\n    if (!create_logical_device(demo)) {\n        return false;\n    }\n    if (!create_sampler(demo)) {\n        return false;\n    }\n    if (!create_descriptor_set_layout(demo)) {\n        return false;\n    }\n    if (!create_swap_chain_related_resources(demo)) {\n        return false;\n    }\n    if (!create_descriptor_pool(demo)) {\n        return false;\n    }\n    if (!create_descriptor_sets(demo)) {\n        return false;\n    }\n    if (!create_command_pool(demo)) {\n        return false;\n    }\n    if (!create_command_buffers(demo)) {\n        return false;\n    }\n    if (!create_semaphores(demo)) {\n        return false;\n    }\n    if (!create_fence(demo)) {\n        return false;\n    }\n    if (!create_demo_texture(demo)) {\n        return false;\n    }\n\n    return true;\n}\n\nbool recreate_swap_chain(struct vulkan_demo *demo) {\n    printf(\"recreating swapchain\\n\");\n    if (!destroy_swap_chain_related_resources(demo)) {\n        return false;\n    }\n    if (!create_swap_chain_related_resources(demo)) {\n        return false;\n    }\n\n    update_descriptor_sets(demo);\n\n    nk_sdl_resize(demo->swap_chain_image_extent.width,\n                  demo->swap_chain_image_extent.height);\n\n    return true;\n}\n\nbool render(struct vulkan_demo *demo, struct nk_colorf *bg,\n            VkSemaphore wait_semaphore, uint32_t image_index) {\n    VkCommandBufferBeginInfo command_buffer_begin_info;\n    VkCommandBuffer command_buffer;\n    VkRenderPassBeginInfo render_pass_info;\n    VkSubmitInfo submit_info;\n    VkPipelineStageFlags wait_stage =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    VkResult result;\n    VkPresentInfoKHR present_info;\n    VkClearValue clear_color;\n\n    memcpy(&clear_color.color, bg, sizeof(VkClearColorValue));\n\n    memset(&command_buffer_begin_info, 0, sizeof(VkCommandBufferBeginInfo));\n    command_buffer_begin_info.sType =\n        VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n    command_buffer = demo->command_buffers[demo->current_in_flight_frame];\n    result = vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkBeginCommandBuffer failed: %d\\n\", result);\n        return false;\n    }\n\n    memset(&render_pass_info, 0, sizeof(VkRenderPassBeginInfo));\n    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;\n    render_pass_info.renderPass = demo->render_pass;\n    render_pass_info.framebuffer = demo->framebuffers[image_index];\n    render_pass_info.renderArea.offset.x = 0;\n    render_pass_info.renderArea.offset.y = 0;\n    render_pass_info.renderArea.extent = demo->swap_chain_image_extent;\n    render_pass_info.clearValueCount = 1;\n    render_pass_info.pClearValues = &clear_color;\n\n    vkCmdBeginRenderPass(command_buffer, &render_pass_info,\n                         VK_SUBPASS_CONTENTS_INLINE);\n\n    vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                      demo->pipeline);\n    vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                            demo->pipeline_layout, 0, 1,\n                            &demo->descriptor_sets[image_index], 0, NULL);\n    vkCmdDraw(command_buffer, 3, 1, 0, 0);\n\n    vkCmdEndRenderPass(command_buffer);\n\n    result = vkEndCommandBuffer(command_buffer);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkEndCommandBuffer failed: %d\\n\", result);\n        return false;\n    }\n\n    memset(&submit_info, 0, sizeof(VkSubmitInfo));\n    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n    submit_info.waitSemaphoreCount = 1;\n    submit_info.pWaitSemaphores = &wait_semaphore;\n    submit_info.pWaitDstStageMask = &wait_stage;\n    submit_info.commandBufferCount = 1;\n    submit_info.pCommandBuffers = &command_buffer;\n    submit_info.signalSemaphoreCount = 1;\n    submit_info.pSignalSemaphores = &demo->render_finished[image_index];\n\n    result = vkQueueSubmit(demo->graphics_queue, 1, &submit_info,\n                           demo->render_fence[demo->current_in_flight_frame]);\n\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkQueueSubmit failed: %d\\n\", result);\n        return false;\n    }\n\n    memset(&present_info, 0, sizeof(VkPresentInfoKHR));\n    present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;\n    present_info.waitSemaphoreCount = 1;\n    present_info.pWaitSemaphores = &demo->render_finished[image_index];\n    present_info.swapchainCount = 1;\n    present_info.pSwapchains = &demo->swap_chain;\n    present_info.pImageIndices = &image_index;\n\n    result = vkQueuePresentKHR(demo->present_queue, &present_info);\n\n    if (result == VK_ERROR_OUT_OF_DATE_KHR) {\n        if (!recreate_swap_chain(demo)) {\n            fprintf(stderr, \"failed to recreate swap chain!\\n\");\n        }\n    } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {\n        fprintf(stderr, \"vkQueuePresentKHR failed: %d\\n\", result);\n        return false;\n    }\n    return true;\n}\n\nVkResult\ndestroy_debug_utils_messenger_ext(VkInstance instance,\n                                  VkDebugUtilsMessengerEXT debugMessenger,\n                                  const VkAllocationCallbacks *pAllocator) {\n    PFN_vkDestroyDebugUtilsMessengerEXT func =\n        (PFN_vkDestroyDebugUtilsMessengerEXT)vkGetInstanceProcAddr(\n            instance, \"vkDestroyDebugUtilsMessengerEXT\");\n    if (func != NULL) {\n        func(instance, debugMessenger, pAllocator);\n        return VK_SUCCESS;\n    } else {\n        return VK_ERROR_EXTENSION_NOT_PRESENT;\n    }\n}\n\nbool cleanup(struct vulkan_demo *demo) {\n    VkResult result;\n    uint32_t i;\n    \n    printf(\"cleaning up\\n\");\n    result = vkDeviceWaitIdle(demo->device);\n    if (result != VK_SUCCESS) {\n        fprintf(stderr, \"vkDeviceWaitIdle failed: %d\\n\", result);\n        return false;\n    }\n\n    destroy_swap_chain_related_resources(demo);\n\n    vkFreeCommandBuffers(demo->device, demo->command_pool,\n                         MAX_IN_FLIGHT_FRAMES, demo->command_buffers);\n    vkDestroyCommandPool(demo->device, demo->command_pool, NULL);\n    vkDestroySampler(demo->device, demo->sampler, NULL);\n    \n    for(i = 0; i < demo->swap_chain_images_len; i++)\n     vkDestroySemaphore(demo->device, demo->render_finished[i], NULL);\n    if(demo->render_finished)\n     free(demo->render_finished);\n     \n    for(i = 0; i < MAX_IN_FLIGHT_FRAMES; i++)\n     vkDestroySemaphore(demo->device, demo->image_available[i], NULL);\n    if(demo->image_available)\n     free(demo->image_available);\n     \n    for(i = 0; i < MAX_IN_FLIGHT_FRAMES; i++)\n    vkDestroyFence(demo->device, demo->render_fence[i], NULL);\n    if(demo->render_fence)\n     free(demo->render_fence);\n    \n    vkDestroyImage(demo->device, demo->demo_texture_image, NULL);\n    vkDestroyImageView(demo->device, demo->demo_texture_image_view, NULL);\n    vkFreeMemory(demo->device, demo->demo_texture_memory, NULL);\n\n    vkDestroyDescriptorSetLayout(demo->device, demo->descriptor_set_layout,\n                                 NULL);\n    vkDestroyDescriptorPool(demo->device, demo->descriptor_pool, NULL);\n\n    vkDestroyDevice(demo->device, NULL);\n    vkDestroySurfaceKHR(demo->instance, demo->surface, NULL);\n\n    if (demo->debug_messenger) {\n        result = destroy_debug_utils_messenger_ext(demo->instance,\n                                                   demo->debug_messenger, NULL);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"Couldn't destroy debug messenger: %d\\n\", result);\n            return false;\n        }\n    }\n    vkDestroyInstance(demo->instance, NULL);\n    if (demo->swap_chain_images) {\n        free(demo->swap_chain_images);\n    }\n    if (demo->swap_chain_image_views) {\n        free(demo->swap_chain_image_views);\n    }\n\n    if (demo->overlay_images) {\n        free(demo->overlay_images);\n    }\n    if (demo->overlay_image_views) {\n        free(demo->overlay_image_views);\n    }\n    if (demo->overlay_image_memories) {\n        free(demo->overlay_image_memories);\n    }\n\n    if (demo->descriptor_sets) {\n        free(demo->descriptor_sets);\n    }\n    if (demo->framebuffers) {\n        free(demo->framebuffers);\n    }\n    if (demo->command_buffers) {\n        free(demo->command_buffers);\n    }\n\n    SDL_DestroyWindow(demo->win);\n\n    return true;\n}\n\nint main(void) {\n    struct vulkan_demo demo;\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n    struct nk_image img;\n    uint32_t image_index;\n    VkResult result;\n    VkSemaphore nk_semaphore;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    SDL_SetHint(SDL_HINT_VIDEO_HIGHDPI_DISABLED, \"0\");\n\n    if (SDL_Init(SDL_INIT_VIDEO) < 0) {\n        fprintf(stderr, \"[SDL] failed to init!\\n\");\n        exit(1);\n    }\n\n    memset(&demo, 0, sizeof(struct vulkan_demo));\n    demo.win = SDL_CreateWindow(\n        \"Demo\", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_WIDTH,\n        WINDOW_HEIGHT,\n        SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);\n\n    if (!create_vulkan_demo(&demo)) {\n        fprintf(stderr, \"failed to create vulkan demo!\\n\");\n        exit(1);\n    }\n    ctx = nk_sdl_init(demo.win, demo.device, demo.physical_device,\n                      demo.indices.graphics, demo.overlay_image_views,\n                      demo.swap_chain_images_len, demo.swap_chain_image_format,\n                      0, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {\n        struct nk_font_atlas *atlas;\n        nk_sdl_font_stash_begin(&atlas);\n        /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas,\n         * \"../../../extra_font/DroidSans.ttf\", 14, 0);*/\n        /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas,\n         * \"../../../extra_font/Roboto-Regular.ttf\", 14, 0);*/\n        /*struct nk_font *future = nk_font_atlas_add_from_file(atlas,\n         * \"../../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n        /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas,\n         * \"../../../extra_font/ProggyClean.ttf\", 12, 0);*/\n        /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas,\n         * \"../../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n        /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas,\n         * \"../../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n        nk_sdl_font_stash_end(demo.graphics_queue);\n        /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n        /*nk_style_set_font(ctx, &droid->handle);*/\n    }\n\n    img = nk_image_ptr(demo.demo_texture_image_view);\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (true) {\n        SDL_Event evt;\n\n        nk_input_begin(ctx);\n        while (SDL_PollEvent(&evt)) {\n            if (evt.type == SDL_QUIT)\n                goto cleanup;\n            if (evt.type == SDL_WINDOWEVENT &&\n                evt.window.event == SDL_WINDOWEVENT_SIZE_CHANGED)\n                recreate_swap_chain(&demo);\n            nk_sdl_handle_event(&evt);\n        }\n        nk_sdl_handle_grab(); /* optional grabbing behavior */\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n                     NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE |\n                         NK_WINDOW_MINIMIZABLE | NK_WINDOW_TITLE)) {\n            enum { EASY, HARD };\n            static int op = EASY;\n            static int property = 20;\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY))\n                op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD))\n                op = HARD;\n\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg),\n                                     nk_vec2(nk_widget_width(ctx), 400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f, 0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f, 0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f, 0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f, 0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* Bindless Texture */\n        if (nk_begin(ctx, \"Texture\", nk_rect(500, 300, 200, 200),\n                     NK_WINDOW_BORDER | NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE |\n                         NK_WINDOW_MINIMIZABLE | NK_WINDOW_TITLE)) {\n            struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);\n            struct nk_rect total_space = nk_window_get_content_region(ctx);\n            nk_draw_image(canvas, total_space, &img, nk_white);\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n#ifdef INCLUDE_CALCULATOR\n        calculator(ctx);\n#endif\n#ifdef INCLUDE_CANVAS\n        canvas(ctx);\n#endif\n#ifdef INCLUDE_OVERVIEW\n        overview(ctx);\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n        style_configurator(ctx, color_table);\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n        node_editor(ctx);\n#endif\n        /* ----------------------------------------- */\n\n        result = vkWaitForFences(demo.device, 1, &demo.render_fence[demo.current_in_flight_frame], VK_TRUE,\n                                 UINT64_MAX);\n                                 \n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkWaitForFences failed: %d\\n\", result);\n            return false;\n        }\n\n        result = vkResetFences(demo.device, 1, &demo.render_fence[demo.current_in_flight_frame]);\n        if (result != VK_SUCCESS) {\n            fprintf(stderr, \"vkResetFences failed: %d\\n\", result);\n            return false;\n        }\n\n        result =\n            vkAcquireNextImageKHR(demo.device, demo.swap_chain, UINT64_MAX,\n                                  demo.image_available[demo.current_in_flight_frame], NULL, &image_index);\n\n        if (result == VK_ERROR_OUT_OF_DATE_KHR) {\n            recreate_swap_chain(&demo);\n\n            /* If vkAcquireNextImageKHR does not successfully acquire an image,\n             * semaphore and fence are unaffected. */\n            continue;\n        }\n        if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {\n            fprintf(stderr, \"vkAcquireNextImageKHR failed: %d\\n\", result);\n            return false;\n        }\n\n        /* Draw */\n        nk_semaphore = nk_sdl_render(demo.graphics_queue, image_index,\n                                     demo.image_available[demo.current_in_flight_frame], NK_ANTI_ALIASING_ON);\n        if (!render(&demo, &bg, nk_semaphore, image_index)) {\n            fprintf(stderr, \"render failed\\n\");\n            return false;\n        }\n        demo.current_in_flight_frame = (demo.current_in_flight_frame + 1) % MAX_IN_FLIGHT_FRAMES;\n    }\ncleanup:\n    nk_sdl_shutdown();\n    cleanup(&demo);\n    SDL_Quit();\n    return 0;\n}\n"
  },
  {
    "path": "demo/sdl_vulkan/nuklear_sdl_vulkan.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warranty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_SDL_VULKAN_H_\n#define NK_SDL_VULKAN_H_\n\nunsigned char nuklearshaders_nuklear_vert_spv[] = {\n  0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x0d, 0x00,\n  0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,\n  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,\n  0x0a, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n  0x2a, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,\n  0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00,\n  0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73,\n  0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64,\n  0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00,\n  0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c,\n  0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f,\n  0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69,\n  0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47,\n  0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,\n  0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00,\n  0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,\n  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00,\n  0x67, 0x6c, 0x5f, 0x50, 0x65, 0x72, 0x56, 0x65, 0x72, 0x74, 0x65, 0x78,\n  0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06, 0x00, 0x08, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x67, 0x6c, 0x5f, 0x50, 0x6f, 0x73, 0x69, 0x74,\n  0x69, 0x6f, 0x6e, 0x00, 0x05, 0x00, 0x03, 0x00, 0x0a, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0e, 0x00, 0x00, 0x00,\n  0x55, 0x6e, 0x69, 0x66, 0x6f, 0x72, 0x6d, 0x42, 0x75, 0x66, 0x66, 0x65,\n  0x72, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x00, 0x06, 0x00, 0x06, 0x00,\n  0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x72, 0x6f, 0x6a,\n  0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,\n  0x10, 0x00, 0x00, 0x00, 0x75, 0x62, 0x6f, 0x00, 0x05, 0x00, 0x05, 0x00,\n  0x16, 0x00, 0x00, 0x00, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e,\n  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x27, 0x00, 0x00, 0x00,\n  0x66, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00,\n  0x05, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x63, 0x6f, 0x6c, 0x6f,\n  0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x04, 0x00, 0x42, 0x00, 0x00, 0x00,\n  0x66, 0x72, 0x61, 0x67, 0x55, 0x76, 0x00, 0x00, 0x05, 0x00, 0x03, 0x00,\n  0x43, 0x00, 0x00, 0x00, 0x75, 0x76, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,\n  0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00,\n  0x02, 0x00, 0x00, 0x00, 0x48, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00,\n  0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x48, 0x00, 0x05, 0x00, 0x0e, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,\n  0x47, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n  0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,\n  0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,\n  0x16, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x47, 0x00, 0x04, 0x00, 0x27, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x2a, 0x00, 0x00, 0x00,\n  0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,\n  0x42, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x47, 0x00, 0x04, 0x00, 0x43, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,\n  0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n  0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x04, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00,\n  0x07, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x09, 0x00, 0x00, 0x00,\n  0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,\n  0x09, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n  0x15, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,\n  0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x04, 0x00,\n  0x0d, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n  0x1e, 0x00, 0x03, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,\n  0x20, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n  0x0e, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00,\n  0x10, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,\n  0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,\n  0x17, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x15, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,\n  0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3f, 0x20, 0x00, 0x04, 0x00,\n  0x1e, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n  0x15, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x21, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,\n  0x22, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x3b, 0x00, 0x04, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,\n  0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00,\n  0x20, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,\n  0x29, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00,\n  0x3b, 0x00, 0x04, 0x00, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,\n  0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x2b, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x7f, 0x43, 0x2b, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x36, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x04, 0x00,\n  0x20, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n  0x20, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n  0x14, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x41, 0x00, 0x00, 0x00,\n  0x42, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,\n  0x15, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x36, 0x00, 0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00,\n  0x05, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x11, 0x00, 0x00, 0x00,\n  0x12, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,\n  0x3d, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n  0x12, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,\n  0x17, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x1b, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,\n  0x1a, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00,\n  0x19, 0x00, 0x00, 0x00, 0x91, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,\n  0x1d, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,\n  0x41, 0x00, 0x05, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00,\n  0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,\n  0x1f, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00,\n  0x22, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00,\n  0x0c, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00,\n  0x7f, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00,\n  0x24, 0x00, 0x00, 0x00, 0x41, 0x00, 0x06, 0x00, 0x22, 0x00, 0x00, 0x00,\n  0x26, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,\n  0x21, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x26, 0x00, 0x00, 0x00,\n  0x25, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00,\n  0x2d, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00,\n  0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00,\n  0x2d, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x2f, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00,\n  0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00,\n  0x32, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n  0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00,\n  0x32, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x34, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,\n  0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00,\n  0x37, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,\n  0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00,\n  0x37, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x39, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00,\n  0x30, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x2c, 0x00, 0x00, 0x00,\n  0x3c, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00,\n  0x3d, 0x00, 0x04, 0x00, 0x20, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00,\n  0x3c, 0x00, 0x00, 0x00, 0x70, 0x00, 0x04, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x3e, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x88, 0x00, 0x05, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00,\n  0x30, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00, 0x00,\n  0x40, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00,\n  0x3a, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,\n  0x27, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,\n  0x14, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00,\n  0x3e, 0x00, 0x03, 0x00, 0x42, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00,\n  0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00\n};\nunsigned int nuklearshaders_nuklear_vert_spv_len = 1856;\nunsigned char nuklearshaders_nuklear_frag_spv[] = {\n  0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x0d, 0x00,\n  0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30,\n  0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x04, 0x00, 0x00, 0x00,\n  0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00,\n  0x11, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n  0x10, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,\n  0x03, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0xc2, 0x01, 0x00, 0x00,\n  0x04, 0x00, 0x09, 0x00, 0x47, 0x4c, 0x5f, 0x41, 0x52, 0x42, 0x5f, 0x73,\n  0x65, 0x70, 0x61, 0x72, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x68, 0x61, 0x64,\n  0x65, 0x72, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x00, 0x00,\n  0x04, 0x00, 0x0a, 0x00, 0x47, 0x4c, 0x5f, 0x47, 0x4f, 0x4f, 0x47, 0x4c,\n  0x45, 0x5f, 0x63, 0x70, 0x70, 0x5f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x5f,\n  0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69,\n  0x76, 0x65, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x47, 0x4c, 0x5f, 0x47,\n  0x4f, 0x4f, 0x47, 0x4c, 0x45, 0x5f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64,\n  0x65, 0x5f, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x00,\n  0x05, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e,\n  0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x09, 0x00, 0x00, 0x00,\n  0x74, 0x65, 0x78, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00,\n  0x05, 0x00, 0x06, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x63, 0x75, 0x72, 0x72,\n  0x65, 0x6e, 0x74, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x00, 0x00,\n  0x05, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67,\n  0x55, 0x76, 0x00, 0x00, 0x05, 0x00, 0x05, 0x00, 0x15, 0x00, 0x00, 0x00,\n  0x6f, 0x75, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x00,\n  0x05, 0x00, 0x05, 0x00, 0x17, 0x00, 0x00, 0x00, 0x66, 0x72, 0x61, 0x67,\n  0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,\n  0x0d, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x47, 0x00, 0x04, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00, 0x11, 0x00, 0x00, 0x00,\n  0x1e, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x00, 0x04, 0x00,\n  0x15, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x47, 0x00, 0x04, 0x00, 0x17, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00,\n  0x21, 0x00, 0x03, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,\n  0x16, 0x00, 0x03, 0x00, 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,\n  0x17, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,\n  0x04, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00,\n  0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x09, 0x00,\n  0x0a, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x03, 0x00,\n  0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,\n  0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,\n  0x3b, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,\n  0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x04, 0x00, 0x0f, 0x00, 0x00, 0x00,\n  0x06, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00,\n  0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,\n  0x3b, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n  0x01, 0x00, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00,\n  0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00,\n  0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,\n  0x20, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,\n  0x07, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x04, 0x00, 0x16, 0x00, 0x00, 0x00,\n  0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x36, 0x00, 0x05, 0x00,\n  0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n  0x03, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x05, 0x00, 0x00, 0x00,\n  0x3b, 0x00, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,\n  0x07, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0b, 0x00, 0x00, 0x00,\n  0x0e, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,\n  0x0f, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,\n  0x57, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00,\n  0x0e, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00,\n  0x09, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00,\n  0x07, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,\n  0x3d, 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n  0x09, 0x00, 0x00, 0x00, 0x85, 0x00, 0x05, 0x00, 0x07, 0x00, 0x00, 0x00,\n  0x1a, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,\n  0x3e, 0x00, 0x03, 0x00, 0x15, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,\n  0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00\n};\nunsigned int nuklearshaders_nuklear_frag_spv_len = 860;\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n#include <SDL2/SDL.h>\n\nenum nk_sdl_init_state { NK_SDL_DEFAULT = 0 };\n\nNK_API struct nk_context *\nnk_sdl_init(SDL_Window *win, VkDevice logical_device,\n            VkPhysicalDevice physical_device,\n            uint32_t graphics_queue_family_index, VkImageView *image_views,\n            uint32_t image_views_len, VkFormat color_format,\n            enum nk_sdl_init_state init_state, VkDeviceSize max_vertex_buffer,\n            VkDeviceSize max_element_buffer);\nNK_API void nk_sdl_shutdown(void);\nNK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void nk_sdl_font_stash_end(VkQueue graphics_queue);\nNK_API int nk_sdl_handle_event(SDL_Event *evt);\nNK_API VkSemaphore nk_sdl_render(VkQueue graphics_queue, uint32_t buffer_index,\n                                 VkSemaphore wait_semaphore,\n                                 enum nk_anti_aliasing AA);\nNK_API void nk_sdl_resize(uint32_t framebuffer_width,\n                          uint32_t framebuffer_height);\nNK_API void nk_sdl_device_destroy(void);\nNK_API void\nnk_sdl_device_create(VkDevice logical_device, VkPhysicalDevice physical_device,\n                     uint32_t graphics_queue_family_index,\n                     VkImageView *image_views, uint32_t image_views_len,\n                     VkFormat color_format, VkDeviceSize max_vertex_buffer,\n                     VkDeviceSize max_element_buffer,\n                     uint32_t framebuffer_width, uint32_t framebuffer_height);\nNK_API void nk_sdl_handle_grab(void);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_SDL_VULKAN_IMPLEMENTATION\n#undef NK_SDL_VULKAN_IMPLEMENTATION\n#include <stdlib.h>\n\n#ifndef NK_SDL_TEXT_MAX\n#define NK_SDL_TEXT_MAX 256\n#endif\n#ifndef NK_SDL_MAX_TEXTURES\n#define NK_SDL_MAX_TEXTURES 256\n#endif\n#ifndef NK_SDL_MAX_KEYS\n#define NK_SDL_MAX_KEYS 32\n#endif\n\n#define VK_COLOR_COMPONENT_MASK_RGBA                                           \\\n    VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |                      \\\n        VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT\n\nstruct nk_sdl_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstruct nk_vulkan_texture_descriptor_set {\n    VkImageView image_view;\n    VkDescriptorSet descriptor_set;\n};\n\nstruct nk_sdl_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    int max_vertex_buffer;\n    int max_element_buffer;\n    VkDevice logical_device;\n    VkPhysicalDevice physical_device;\n    VkImageView *image_views;\n    uint32_t image_views_len;\n    VkFormat color_format;\n    VkFramebuffer *framebuffers;\n    uint32_t framebuffers_len;\n    VkCommandBuffer *command_buffers;\n    uint32_t command_buffers_len;\n    VkSampler sampler;\n    VkCommandPool command_pool;\n    VkSemaphore render_completed;\n    VkBuffer vertex_buffer;\n    VkDeviceMemory vertex_memory;\n    void *mapped_vertex;\n    VkBuffer index_buffer;\n    VkDeviceMemory index_memory;\n    void *mapped_index;\n    VkBuffer uniform_buffer;\n    VkDeviceMemory uniform_memory;\n    void *mapped_uniform;\n    VkRenderPass render_pass;\n    VkDescriptorPool descriptor_pool;\n    VkDescriptorSetLayout uniform_descriptor_set_layout;\n    VkDescriptorSet uniform_descriptor_set;\n    VkDescriptorSetLayout texture_descriptor_set_layout;\n    struct nk_vulkan_texture_descriptor_set *texture_descriptor_sets;\n    uint32_t texture_descriptor_sets_len;\n    VkPipelineLayout pipeline_layout;\n    VkPipeline pipeline;\n    VkImage font_image;\n    VkImageView font_image_view;\n    VkDeviceMemory font_memory;\n};\n\nstatic struct nk_sdl {\n    SDL_Window *win;\n    int width, height;\n    int display_width, display_height;\n    struct nk_sdl_device vulkan;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    unsigned int text[NK_SDL_TEXT_MAX];\n    int text_len;\n    struct nk_vec2 scroll;\n    uint64_t delta_time_milliseconds_last;\n} sdl;\n\nstruct Mat4f {\n    float m[16];\n};\n\nNK_INTERN uint32_t nk_sdl_find_memory_index(VkPhysicalDevice physical_device,\n                                            uint32_t type_filter,\n                                            VkMemoryPropertyFlags properties) {\n    VkPhysicalDeviceMemoryProperties mem_properties;\n    uint32_t i;\n\n    vkGetPhysicalDeviceMemoryProperties(physical_device, &mem_properties);\n    for (i = 0; i < mem_properties.memoryTypeCount; i++) {\n        if ((type_filter & (1 << i)) &&\n            (mem_properties.memoryTypes[i].propertyFlags & properties) ==\n                properties) {\n            return i;\n        }\n    }\n\n    assert(0);\n    return 0;\n}\n\nNK_INTERN void nk_sdl_create_sampler(struct nk_sdl_device *dev) {\n    VkResult result;\n    VkSamplerCreateInfo sampler_info;\n    memset(&sampler_info, 0, sizeof(VkSamplerCreateInfo));\n\n    sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n    sampler_info.pNext = NULL;\n    sampler_info.maxAnisotropy = 1.0;\n    sampler_info.magFilter = VK_FILTER_LINEAR;\n    sampler_info.minFilter = VK_FILTER_LINEAR;\n    sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n    sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.mipLodBias = 0.0f;\n    sampler_info.compareEnable = VK_FALSE;\n    sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;\n    sampler_info.minLod = 0.0f;\n    sampler_info.maxLod = 0.0f;\n    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;\n\n    result = vkCreateSampler(dev->logical_device, &sampler_info, NULL,\n                             &dev->sampler);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_sdl_create_command_pool(struct nk_sdl_device *dev,\n                           uint32_t graphics_queue_family_index) {\n    VkResult result;\n    VkCommandPoolCreateInfo pool_info;\n    memset(&pool_info, 0, sizeof(VkCommandPoolCreateInfo));\n\n    pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;\n    pool_info.queueFamilyIndex = graphics_queue_family_index;\n    pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;\n    result = vkCreateCommandPool(dev->logical_device, &pool_info, NULL,\n                                 &dev->command_pool);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_sdl_create_command_buffers(struct nk_sdl_device *dev) {\n    VkResult result;\n    VkCommandBufferAllocateInfo allocate_info;\n    memset(&allocate_info, 0, sizeof(VkCommandBufferAllocateInfo));\n\n    dev->command_buffers = (VkCommandBuffer *)malloc(dev->image_views_len *\n                                                     sizeof(VkCommandBuffer));\n    dev->command_buffers_len = dev->image_views_len;\n\n    allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;\n    allocate_info.commandPool = dev->command_pool;\n    allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;\n    allocate_info.commandBufferCount = dev->command_buffers_len;\n\n    result = vkAllocateCommandBuffers(dev->logical_device, &allocate_info,\n                                      dev->command_buffers);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_sdl_create_semaphore(struct nk_sdl_device *dev) {\n    VkResult result;\n    VkSemaphoreCreateInfo semaphore_info;\n    memset(&semaphore_info, 0, sizeof(VkSemaphoreCreateInfo));\n\n    semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;\n    result = (vkCreateSemaphore(dev->logical_device, &semaphore_info, NULL,\n                                &dev->render_completed));\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_sdl_create_buffer_and_memory(struct nk_sdl_device *dev,\n                                               VkBuffer *buffer,\n                                               VkBufferUsageFlags usage,\n                                               VkDeviceMemory *memory,\n                                               VkDeviceSize size) {\n    VkMemoryRequirements mem_reqs;\n    VkResult result;\n    VkBufferCreateInfo buffer_info;\n    VkMemoryAllocateInfo alloc_info;\n\n    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));\n    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n    buffer_info.size = size;\n    buffer_info.usage = usage;\n    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    result = vkCreateBuffer(dev->logical_device, &buffer_info, NULL, buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkGetBufferMemoryRequirements(dev->logical_device, *buffer, &mem_reqs);\n\n    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n    alloc_info.allocationSize = mem_reqs.size;\n    alloc_info.memoryTypeIndex =\n        nk_sdl_find_memory_index(dev->physical_device, mem_reqs.memoryTypeBits,\n                                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n                                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\n    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL, memory);\n    NK_ASSERT(result == VK_SUCCESS);\n    result = vkBindBufferMemory(dev->logical_device, *buffer, *memory, 0);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_sdl_create_render_pass(struct nk_sdl_device *dev) {\n    VkAttachmentDescription attachment;\n    VkAttachmentReference color_reference;\n    VkSubpassDependency subpass_dependency;\n    VkSubpassDescription subpass_description;\n    VkRenderPassCreateInfo render_pass_info;\n    VkResult result;\n\n    memset(&attachment, 0, sizeof(VkAttachmentDescription));\n    attachment.format = dev->color_format;\n    attachment.samples = VK_SAMPLE_COUNT_1_BIT;\n    attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;\n    attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n    attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n    attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n    attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    attachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n\n    memset(&color_reference, 0, sizeof(VkAttachmentReference));\n    color_reference.attachment = 0;\n    color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;\n\n    memset(&subpass_dependency, 0, sizeof(VkSubpassDependency));\n    subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;\n    subpass_dependency.srcAccessMask = 0;\n    subpass_dependency.srcStageMask =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    subpass_dependency.dstSubpass = 0;\n    subpass_dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |\n                                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n    subpass_dependency.dstStageMask =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n\n    memset(&subpass_description, 0, sizeof(VkSubpassDescription));\n    subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;\n    subpass_description.colorAttachmentCount = 1;\n    subpass_description.pColorAttachments = &color_reference;\n\n    memset(&render_pass_info, 0, sizeof(VkRenderPassCreateInfo));\n    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;\n    render_pass_info.attachmentCount = 1;\n    render_pass_info.pAttachments = &attachment;\n    render_pass_info.subpassCount = 1;\n    render_pass_info.pSubpasses = &subpass_description;\n    render_pass_info.dependencyCount = 1;\n    render_pass_info.pDependencies = &subpass_dependency;\n\n    result = vkCreateRenderPass(dev->logical_device, &render_pass_info, NULL,\n                                &dev->render_pass);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_sdl_create_framebuffers(struct nk_sdl_device *dev,\n                                          uint32_t framebuffer_width,\n                                          uint32_t framebuffer_height) {\n\n    VkFramebufferCreateInfo framebuffer_create_info;\n    uint32_t i;\n    VkResult result;\n\n    dev->framebuffers =\n        (VkFramebuffer *)malloc(dev->image_views_len * sizeof(VkFramebuffer));\n\n    memset(&framebuffer_create_info, 0, sizeof(VkFramebufferCreateInfo));\n    framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;\n    framebuffer_create_info.renderPass = dev->render_pass;\n    framebuffer_create_info.attachmentCount = 1;\n    framebuffer_create_info.width = framebuffer_width;\n    framebuffer_create_info.height = framebuffer_height;\n    framebuffer_create_info.layers = 1;\n    for (i = 0; i < dev->image_views_len; i++) {\n        framebuffer_create_info.pAttachments = &dev->image_views[i];\n        result =\n            vkCreateFramebuffer(dev->logical_device, &framebuffer_create_info,\n                                NULL, &dev->framebuffers[i]);\n        NK_ASSERT(result == VK_SUCCESS);\n    }\n    dev->framebuffers_len = dev->image_views_len;\n}\n\nNK_INTERN void nk_sdl_create_descriptor_pool(struct nk_sdl_device *dev) {\n    VkDescriptorPoolSize pool_sizes[2];\n    VkDescriptorPoolCreateInfo pool_info;\n    VkResult result;\n\n    memset(&pool_sizes, 0, sizeof(VkDescriptorPoolSize) * 2);\n    pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n    pool_sizes[0].descriptorCount = 1;\n    pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    pool_sizes[1].descriptorCount = NK_SDL_MAX_TEXTURES;\n\n    memset(&pool_info, 0, sizeof(VkDescriptorPoolCreateInfo));\n    pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;\n    pool_info.poolSizeCount = 2;\n    pool_info.pPoolSizes = pool_sizes;\n    pool_info.maxSets = 1 + NK_SDL_MAX_TEXTURES;\n\n    result = vkCreateDescriptorPool(dev->logical_device, &pool_info, NULL,\n                                    &dev->descriptor_pool);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_sdl_create_uniform_descriptor_set_layout(struct nk_sdl_device *dev) {\n    VkDescriptorSetLayoutBinding binding;\n    VkDescriptorSetLayoutCreateInfo descriptor_set_info;\n    VkResult result;\n\n    memset(&binding, 0, sizeof(VkDescriptorSetLayoutBinding));\n    binding.binding = 0;\n    binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n    binding.descriptorCount = 1;\n    binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;\n\n    memset(&descriptor_set_info, 0, sizeof(VkDescriptorSetLayoutCreateInfo));\n    descriptor_set_info.sType =\n        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n    descriptor_set_info.bindingCount = 1;\n    descriptor_set_info.pBindings = &binding;\n\n    result =\n        vkCreateDescriptorSetLayout(dev->logical_device, &descriptor_set_info,\n                                    NULL, &dev->uniform_descriptor_set_layout);\n\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_sdl_create_and_update_uniform_descriptor_set(struct nk_sdl_device *dev) {\n    VkDescriptorSetAllocateInfo allocate_info;\n    VkDescriptorBufferInfo buffer_info;\n    VkWriteDescriptorSet descriptor_write;\n    VkResult result;\n\n    memset(&allocate_info, 0, sizeof(VkDescriptorSetAllocateInfo));\n    allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n    allocate_info.descriptorPool = dev->descriptor_pool;\n    allocate_info.descriptorSetCount = 1;\n    allocate_info.pSetLayouts = &dev->uniform_descriptor_set_layout;\n\n    result = vkAllocateDescriptorSets(dev->logical_device, &allocate_info,\n                                      &dev->uniform_descriptor_set);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&buffer_info, 0, sizeof(VkDescriptorBufferInfo));\n    buffer_info.buffer = dev->uniform_buffer;\n    buffer_info.offset = 0;\n    buffer_info.range = sizeof(struct Mat4f);\n\n    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));\n    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n    descriptor_write.dstSet = dev->uniform_descriptor_set;\n    descriptor_write.dstBinding = 0;\n    descriptor_write.dstArrayElement = 0;\n    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n    descriptor_write.descriptorCount = 1;\n    descriptor_write.pBufferInfo = &buffer_info;\n\n    vkUpdateDescriptorSets(dev->logical_device, 1, &descriptor_write, 0, NULL);\n}\n\nNK_INTERN void\nnk_sdl_create_texture_descriptor_set_layout(struct nk_sdl_device *dev) {\n    VkDescriptorSetLayoutBinding binding;\n    VkDescriptorSetLayoutCreateInfo descriptor_set_info;\n    VkResult result;\n\n    memset(&binding, 0, sizeof(VkDescriptorSetLayoutBinding));\n    binding.binding = 0;\n    binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    binding.descriptorCount = 1;\n    binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;\n\n    memset(&descriptor_set_info, 0, sizeof(VkDescriptorSetLayoutCreateInfo));\n    descriptor_set_info.sType =\n        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n    descriptor_set_info.bindingCount = 1;\n    descriptor_set_info.pBindings = &binding;\n\n    result =\n        vkCreateDescriptorSetLayout(dev->logical_device, &descriptor_set_info,\n                                    NULL, &dev->texture_descriptor_set_layout);\n\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_sdl_create_texture_descriptor_sets(struct nk_sdl_device *dev) {\n    VkDescriptorSetLayout *descriptor_set_layouts;\n    VkDescriptorSet *descriptor_sets;\n    VkDescriptorSetAllocateInfo allocate_info;\n    VkResult result;\n    int i;\n\n    descriptor_set_layouts = (VkDescriptorSetLayout *)malloc(\n        NK_SDL_MAX_TEXTURES * sizeof(VkDescriptorSetLayout));\n    descriptor_sets = (VkDescriptorSet *)malloc(NK_SDL_MAX_TEXTURES *\n                                                sizeof(VkDescriptorSet));\n\n    dev->texture_descriptor_sets =\n        (struct nk_vulkan_texture_descriptor_set *)malloc(\n            NK_SDL_MAX_TEXTURES *\n            sizeof(struct nk_vulkan_texture_descriptor_set));\n    dev->texture_descriptor_sets_len = 0;\n\n    for (i = 0; i < NK_SDL_MAX_TEXTURES; i++) {\n        descriptor_set_layouts[i] = dev->texture_descriptor_set_layout;\n        descriptor_sets[i] = dev->texture_descriptor_sets[i].descriptor_set;\n    }\n\n    memset(&allocate_info, 0, sizeof(VkDescriptorSetAllocateInfo));\n    allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n    allocate_info.descriptorPool = dev->descriptor_pool;\n    allocate_info.descriptorSetCount = NK_SDL_MAX_TEXTURES;\n    allocate_info.pSetLayouts = descriptor_set_layouts;\n\n    result = vkAllocateDescriptorSets(dev->logical_device, &allocate_info,\n                                      descriptor_sets);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    for (i = 0; i < NK_SDL_MAX_TEXTURES; i++) {\n        dev->texture_descriptor_sets[i].descriptor_set = descriptor_sets[i];\n    }\n    free(descriptor_set_layouts);\n    free(descriptor_sets);\n}\n\nNK_INTERN void nk_sdl_create_pipeline_layout(struct nk_sdl_device *dev) {\n    VkPipelineLayoutCreateInfo pipeline_layout_info;\n    VkDescriptorSetLayout descriptor_set_layouts[2];\n    VkResult result;\n\n    descriptor_set_layouts[0] = dev->uniform_descriptor_set_layout;\n    descriptor_set_layouts[1] = dev->texture_descriptor_set_layout;\n\n    memset(&pipeline_layout_info, 0, sizeof(VkPipelineLayoutCreateInfo));\n    pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;\n    pipeline_layout_info.setLayoutCount = 2;\n    pipeline_layout_info.pSetLayouts = descriptor_set_layouts;\n\n    result = (vkCreatePipelineLayout(dev->logical_device, &pipeline_layout_info,\n                                     NULL, &dev->pipeline_layout));\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN VkPipelineShaderStageCreateInfo\nnk_sdl_create_shader(struct nk_sdl_device *dev, unsigned char *spv_shader,\n                     uint32_t size, VkShaderStageFlagBits stage_bit) {\n    VkShaderModuleCreateInfo create_info;\n    VkPipelineShaderStageCreateInfo shader_info;\n    VkShaderModule module = NULL;\n    VkResult result;\n\n    memset(&create_info, 0, sizeof(VkShaderModuleCreateInfo));\n    create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;\n    create_info.codeSize = size;\n    create_info.pCode = (const uint32_t *)spv_shader;\n    result =\n        vkCreateShaderModule(dev->logical_device, &create_info, NULL, &module);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&shader_info, 0, sizeof(VkPipelineShaderStageCreateInfo));\n    shader_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;\n    shader_info.stage = stage_bit;\n    shader_info.module = module;\n    shader_info.pName = \"main\";\n    return shader_info;\n}\n\nNK_INTERN void nk_sdl_create_pipeline(struct nk_sdl_device *dev) {\n    VkPipelineInputAssemblyStateCreateInfo input_assembly_state;\n    VkPipelineRasterizationStateCreateInfo rasterization_state;\n    VkPipelineColorBlendAttachmentState attachment_state = {\n        VK_TRUE,\n        VK_BLEND_FACTOR_SRC_ALPHA,\n        VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,\n        VK_BLEND_OP_ADD,\n        VK_BLEND_FACTOR_SRC_ALPHA,\n        VK_BLEND_FACTOR_ONE,\n        VK_BLEND_OP_ADD,\n        VK_COLOR_COMPONENT_MASK_RGBA,\n    };\n    VkPipelineColorBlendStateCreateInfo color_blend_state;\n    VkPipelineViewportStateCreateInfo viewport_state;\n    VkPipelineMultisampleStateCreateInfo multisample_state;\n    VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT,\n                                        VK_DYNAMIC_STATE_SCISSOR};\n    VkPipelineDynamicStateCreateInfo dynamic_state;\n    VkPipelineShaderStageCreateInfo shader_stages[2];\n    VkVertexInputBindingDescription vertex_input_info;\n    VkVertexInputAttributeDescription vertex_attribute_description[3];\n    VkPipelineVertexInputStateCreateInfo vertex_input;\n    VkGraphicsPipelineCreateInfo pipeline_info;\n    VkResult result;\n\n    memset(&input_assembly_state, 0,\n           sizeof(VkPipelineInputAssemblyStateCreateInfo));\n    input_assembly_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;\n    input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;\n    input_assembly_state.primitiveRestartEnable = VK_FALSE;\n\n    memset(&rasterization_state, 0,\n           sizeof(VkPipelineRasterizationStateCreateInfo));\n    rasterization_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;\n    rasterization_state.polygonMode = VK_POLYGON_MODE_FILL;\n    rasterization_state.cullMode = VK_CULL_MODE_NONE;\n    rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;\n    rasterization_state.lineWidth = 1.0f;\n\n    memset(&color_blend_state, 0, sizeof(VkPipelineColorBlendStateCreateInfo));\n    color_blend_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;\n    color_blend_state.attachmentCount = 1;\n    color_blend_state.pAttachments = &attachment_state;\n\n    memset(&viewport_state, 0, sizeof(VkPipelineViewportStateCreateInfo));\n    viewport_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;\n    viewport_state.viewportCount = 1;\n    viewport_state.scissorCount = 1;\n\n    memset(&multisample_state, 0, sizeof(VkPipelineMultisampleStateCreateInfo));\n    multisample_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;\n    multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;\n\n    memset(&dynamic_state, 0, sizeof(VkPipelineDynamicStateCreateInfo));\n    dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;\n    dynamic_state.pDynamicStates = dynamic_states;\n    dynamic_state.dynamicStateCount = 2;\n\n    shader_stages[0] = nk_sdl_create_shader(\n        dev, nuklearshaders_nuklear_vert_spv,\n        nuklearshaders_nuklear_vert_spv_len, VK_SHADER_STAGE_VERTEX_BIT);\n    shader_stages[1] = nk_sdl_create_shader(\n        dev, nuklearshaders_nuklear_frag_spv,\n        nuklearshaders_nuklear_frag_spv_len, VK_SHADER_STAGE_FRAGMENT_BIT);\n\n    memset(&vertex_input_info, 0, sizeof(VkVertexInputBindingDescription));\n    vertex_input_info.binding = 0;\n    vertex_input_info.stride = sizeof(struct nk_sdl_vertex);\n    vertex_input_info.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;\n\n    memset(&vertex_attribute_description, 0,\n           sizeof(VkVertexInputAttributeDescription) * 3);\n    vertex_attribute_description[0].location = 0;\n    vertex_attribute_description[0].format = VK_FORMAT_R32G32_SFLOAT;\n    vertex_attribute_description[0].offset =\n        NK_OFFSETOF(struct nk_sdl_vertex, position);\n    vertex_attribute_description[1].location = 1;\n    vertex_attribute_description[1].format = VK_FORMAT_R32G32_SFLOAT;\n    vertex_attribute_description[1].offset =\n        NK_OFFSETOF(struct nk_sdl_vertex, uv);\n    vertex_attribute_description[2].location = 2;\n    vertex_attribute_description[2].format = VK_FORMAT_R8G8B8A8_UINT;\n    vertex_attribute_description[2].offset =\n        NK_OFFSETOF(struct nk_sdl_vertex, col);\n\n    memset(&vertex_input, 0, sizeof(VkPipelineVertexInputStateCreateInfo));\n    vertex_input.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;\n    vertex_input.vertexBindingDescriptionCount = 1;\n    vertex_input.pVertexBindingDescriptions = &vertex_input_info;\n    vertex_input.vertexAttributeDescriptionCount = 3;\n    vertex_input.pVertexAttributeDescriptions = vertex_attribute_description;\n\n    memset(&pipeline_info, 0, sizeof(VkGraphicsPipelineCreateInfo));\n    pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;\n    pipeline_info.flags = 0;\n    pipeline_info.stageCount = 2;\n    pipeline_info.pStages = shader_stages;\n    pipeline_info.pVertexInputState = &vertex_input;\n    pipeline_info.pInputAssemblyState = &input_assembly_state;\n    pipeline_info.pViewportState = &viewport_state;\n    pipeline_info.pRasterizationState = &rasterization_state;\n    pipeline_info.pMultisampleState = &multisample_state;\n    pipeline_info.pColorBlendState = &color_blend_state;\n    pipeline_info.pDynamicState = &dynamic_state;\n    pipeline_info.layout = dev->pipeline_layout;\n    pipeline_info.renderPass = dev->render_pass;\n    pipeline_info.basePipelineIndex = -1;\n    pipeline_info.basePipelineHandle = NULL;\n\n    result = vkCreateGraphicsPipelines(dev->logical_device, NULL, 1,\n                                       &pipeline_info, NULL, &dev->pipeline);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkDestroyShaderModule(dev->logical_device, shader_stages[0].module, NULL);\n    vkDestroyShaderModule(dev->logical_device, shader_stages[1].module, NULL);\n}\n\nNK_INTERN void nk_sdl_create_render_resources(struct nk_sdl_device *dev,\n                                              uint32_t framebuffer_width,\n                                              uint32_t framebuffer_height) {\n    nk_sdl_create_render_pass(dev);\n    nk_sdl_create_framebuffers(dev, framebuffer_width, framebuffer_height);\n    nk_sdl_create_descriptor_pool(dev);\n    nk_sdl_create_uniform_descriptor_set_layout(dev);\n    nk_sdl_create_and_update_uniform_descriptor_set(dev);\n    nk_sdl_create_texture_descriptor_set_layout(dev);\n    nk_sdl_create_texture_descriptor_sets(dev);\n    nk_sdl_create_pipeline_layout(dev);\n    nk_sdl_create_pipeline(dev);\n}\n\nNK_API void\nnk_sdl_device_create(VkDevice logical_device, VkPhysicalDevice physical_device,\n                     uint32_t graphics_queue_family_index,\n                     VkImageView *image_views, uint32_t image_views_len,\n                     VkFormat color_format, VkDeviceSize max_vertex_buffer,\n                     VkDeviceSize max_element_buffer,\n                     uint32_t framebuffer_width, uint32_t framebuffer_height) {\n    struct nk_sdl_device *dev = &sdl.vulkan;\n    dev->max_vertex_buffer = max_vertex_buffer;\n    dev->max_element_buffer = max_element_buffer;\n    nk_buffer_init_default(&dev->cmds);\n    dev->logical_device = logical_device;\n    dev->physical_device = physical_device;\n    dev->image_views = image_views;\n    dev->image_views_len = image_views_len;\n    dev->color_format = color_format;\n    dev->framebuffers = NULL;\n    dev->framebuffers_len = 0;\n\n    nk_sdl_create_sampler(dev);\n    nk_sdl_create_command_pool(dev, graphics_queue_family_index);\n    nk_sdl_create_command_buffers(dev);\n    nk_sdl_create_semaphore(dev);\n\n    nk_sdl_create_buffer_and_memory(dev, &dev->vertex_buffer,\n                                    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,\n                                    &dev->vertex_memory, max_vertex_buffer);\n    nk_sdl_create_buffer_and_memory(dev, &dev->index_buffer,\n                                    VK_BUFFER_USAGE_INDEX_BUFFER_BIT,\n                                    &dev->index_memory, max_element_buffer);\n    nk_sdl_create_buffer_and_memory(dev, &dev->uniform_buffer,\n                                    VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,\n                                    &dev->uniform_memory, sizeof(struct Mat4f));\n\n    vkMapMemory(dev->logical_device, dev->vertex_memory, 0, max_vertex_buffer,\n                0, &dev->mapped_vertex);\n    vkMapMemory(dev->logical_device, dev->index_memory, 0, max_element_buffer,\n                0, &dev->mapped_index);\n    vkMapMemory(dev->logical_device, dev->uniform_memory, 0,\n                sizeof(struct Mat4f), 0, &dev->mapped_uniform);\n\n    nk_sdl_create_render_resources(dev, framebuffer_width, framebuffer_height);\n}\n\nNK_INTERN void nk_sdl_device_upload_atlas(VkQueue graphics_queue,\n                                          const void *image, int width,\n                                          int height) {\n    struct nk_sdl_device *dev = &sdl.vulkan;\n\n    VkImageCreateInfo image_info;\n    VkResult result;\n    VkMemoryRequirements mem_reqs;\n    VkMemoryAllocateInfo alloc_info;\n    VkBufferCreateInfo buffer_info;\n    uint8_t *data = 0;\n    VkCommandBufferBeginInfo begin_info;\n    VkCommandBuffer command_buffer;\n    VkImageMemoryBarrier image_memory_barrier;\n    VkBufferImageCopy buffer_copy_region;\n    VkImageMemoryBarrier image_shader_memory_barrier;\n    VkFence fence;\n    VkFenceCreateInfo fence_create;\n    VkSubmitInfo submit_info;\n    VkImageViewCreateInfo image_view_info;\n    struct {\n        VkDeviceMemory memory;\n        VkBuffer buffer;\n    } staging_buffer;\n\n    memset(&image_info, 0, sizeof(VkImageCreateInfo));\n    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n    image_info.imageType = VK_IMAGE_TYPE_2D;\n    image_info.format = VK_FORMAT_R8G8B8A8_UNORM;\n    image_info.extent.width = (uint32_t)width;\n    image_info.extent.height = (uint32_t)height;\n    image_info.extent.depth = 1;\n    image_info.mipLevels = 1;\n    image_info.arrayLayers = 1;\n    image_info.samples = VK_SAMPLE_COUNT_1_BIT;\n    image_info.tiling = VK_IMAGE_TILING_OPTIMAL;\n    image_info.usage =\n        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;\n    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\n    result =\n        vkCreateImage(dev->logical_device, &image_info, NULL, &dev->font_image);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkGetImageMemoryRequirements(dev->logical_device, dev->font_image,\n                                 &mem_reqs);\n\n    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n    alloc_info.allocationSize = mem_reqs.size;\n    alloc_info.memoryTypeIndex =\n        nk_sdl_find_memory_index(dev->physical_device, mem_reqs.memoryTypeBits,\n                                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);\n\n    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL,\n                              &dev->font_memory);\n    NK_ASSERT(result == VK_SUCCESS);\n    result = vkBindImageMemory(dev->logical_device, dev->font_image,\n                               dev->font_memory, 0);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));\n    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n    buffer_info.size = alloc_info.allocationSize;\n    buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;\n    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    result = vkCreateBuffer(dev->logical_device, &buffer_info, NULL,\n                            &staging_buffer.buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n    vkGetBufferMemoryRequirements(dev->logical_device, staging_buffer.buffer,\n                                  &mem_reqs);\n\n    alloc_info.allocationSize = mem_reqs.size;\n    alloc_info.memoryTypeIndex =\n        nk_sdl_find_memory_index(dev->physical_device, mem_reqs.memoryTypeBits,\n                                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n                                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\n    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL,\n                              &staging_buffer.memory);\n    NK_ASSERT(result == VK_SUCCESS);\n    result = vkBindBufferMemory(dev->logical_device, staging_buffer.buffer,\n                                staging_buffer.memory, 0);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    result = vkMapMemory(dev->logical_device, staging_buffer.memory, 0,\n                         alloc_info.allocationSize, 0, (void **)&data);\n    NK_ASSERT(result == VK_SUCCESS);\n    memcpy(data, image, width * height * 4);\n    vkUnmapMemory(dev->logical_device, staging_buffer.memory);\n\n    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));\n    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n    NK_ASSERT(dev->command_buffers_len > 0);\n    /*\n    use the same command buffer as for render as we are regenerating the\n    buffer during render anyway\n    */\n    command_buffer = dev->command_buffers[0];\n    result = vkBeginCommandBuffer(command_buffer, &begin_info);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&image_memory_barrier, 0, sizeof(VkImageMemoryBarrier));\n    image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n    image_memory_barrier.image = dev->font_image;\n    image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n    image_memory_barrier.subresourceRange.aspectMask =\n        VK_IMAGE_ASPECT_COLOR_BIT;\n    image_memory_barrier.subresourceRange.levelCount = 1;\n    image_memory_barrier.subresourceRange.layerCount = 1;\n    image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;\n\n    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\n                         VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,\n                         &image_memory_barrier);\n\n    memset(&buffer_copy_region, 0, sizeof(VkBufferImageCopy));\n    buffer_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    buffer_copy_region.imageSubresource.layerCount = 1;\n    buffer_copy_region.imageExtent.width = (uint32_t)width;\n    buffer_copy_region.imageExtent.height = (uint32_t)height;\n    buffer_copy_region.imageExtent.depth = 1;\n\n    vkCmdCopyBufferToImage(\n        command_buffer, staging_buffer.buffer, dev->font_image,\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_copy_region);\n\n    memset(&image_shader_memory_barrier, 0, sizeof(VkImageMemoryBarrier));\n    image_shader_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n    image_shader_memory_barrier.image = dev->font_image;\n    image_shader_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_shader_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_shader_memory_barrier.oldLayout =\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n    image_shader_memory_barrier.newLayout =\n        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n    image_shader_memory_barrier.subresourceRange.aspectMask =\n        VK_IMAGE_ASPECT_COLOR_BIT;\n    image_shader_memory_barrier.subresourceRange.levelCount = 1;\n    image_shader_memory_barrier.subresourceRange.layerCount = 1;\n    image_shader_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,\n    image_shader_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,\n\n    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,\n                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0,\n                         NULL, 1, &image_shader_memory_barrier);\n\n    result = vkEndCommandBuffer(command_buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&fence_create, 0, sizeof(VkFenceCreateInfo));\n    fence_create.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;\n\n    result = vkCreateFence(dev->logical_device, &fence_create, NULL, &fence);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&submit_info, 0, sizeof(VkSubmitInfo));\n    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n    submit_info.commandBufferCount = 1;\n    submit_info.pCommandBuffers = &command_buffer;\n\n    result = vkQueueSubmit(graphics_queue, 1, &submit_info, fence);\n    NK_ASSERT(result == VK_SUCCESS);\n    result =\n        vkWaitForFences(dev->logical_device, 1, &fence, VK_TRUE, UINT64_MAX);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkDestroyFence(dev->logical_device, fence, NULL);\n\n    vkFreeMemory(dev->logical_device, staging_buffer.memory, NULL);\n    vkDestroyBuffer(dev->logical_device, staging_buffer.buffer, NULL);\n\n    memset(&image_view_info, 0, sizeof(VkImageViewCreateInfo));\n    image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n    image_view_info.image = dev->font_image;\n    image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n    image_view_info.format = image_info.format;\n    image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    image_view_info.subresourceRange.layerCount = 1;\n    image_view_info.subresourceRange.levelCount = 1;\n\n    result = vkCreateImageView(dev->logical_device, &image_view_info, NULL,\n                               &dev->font_image_view);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_sdl_destroy_render_resources(struct nk_sdl_device *dev) {\n    uint32_t i;\n\n    vkDestroyPipeline(dev->logical_device, dev->pipeline, NULL);\n    vkDestroyPipelineLayout(dev->logical_device, dev->pipeline_layout, NULL);\n    vkDestroyDescriptorSetLayout(dev->logical_device,\n                                 dev->texture_descriptor_set_layout, NULL);\n    vkDestroyDescriptorSetLayout(dev->logical_device,\n                                 dev->uniform_descriptor_set_layout, NULL);\n    vkDestroyDescriptorPool(dev->logical_device, dev->descriptor_pool, NULL);\n    for (i = 0; i < dev->framebuffers_len; i++) {\n        vkDestroyFramebuffer(dev->logical_device, dev->framebuffers[i], NULL);\n    }\n    free(dev->framebuffers);\n    dev->framebuffers_len = 0;\n    free(dev->texture_descriptor_sets);\n    dev->texture_descriptor_sets_len = 0;\n    vkDestroyRenderPass(dev->logical_device, dev->render_pass, NULL);\n}\n\nNK_API void nk_sdl_resize(uint32_t framebuffer_width,\n                          uint32_t framebuffer_height) {\n    struct nk_sdl_device *dev = &sdl.vulkan;\n\n    SDL_GetWindowSize(sdl.win, &sdl.width, &sdl.height);\n    sdl.display_width = framebuffer_width;\n    sdl.display_height = framebuffer_height;\n\n    nk_sdl_destroy_render_resources(dev);\n    nk_sdl_create_render_resources(dev, sdl.display_width, sdl.display_height);\n}\n\nNK_API void nk_sdl_device_destroy(void) {\n    struct nk_sdl_device *dev = &sdl.vulkan;\n\n    vkDeviceWaitIdle(dev->logical_device);\n\n    nk_sdl_destroy_render_resources(dev);\n\n    vkFreeCommandBuffers(dev->logical_device, dev->command_pool,\n                         dev->command_buffers_len, dev->command_buffers);\n    vkDestroyCommandPool(dev->logical_device, dev->command_pool, NULL);\n    vkDestroySemaphore(dev->logical_device, dev->render_completed, NULL);\n\n    vkUnmapMemory(dev->logical_device, dev->vertex_memory);\n    vkUnmapMemory(dev->logical_device, dev->index_memory);\n    vkUnmapMemory(dev->logical_device, dev->uniform_memory);\n\n    vkFreeMemory(dev->logical_device, dev->vertex_memory, NULL);\n    vkFreeMemory(dev->logical_device, dev->index_memory, NULL);\n    vkFreeMemory(dev->logical_device, dev->uniform_memory, NULL);\n\n    vkDestroyBuffer(dev->logical_device, dev->vertex_buffer, NULL);\n    vkDestroyBuffer(dev->logical_device, dev->index_buffer, NULL);\n    vkDestroyBuffer(dev->logical_device, dev->uniform_buffer, NULL);\n\n    vkDestroySampler(dev->logical_device, dev->sampler, NULL);\n\n    vkFreeMemory(dev->logical_device, dev->font_memory, NULL);\n    vkDestroyImage(dev->logical_device, dev->font_image, NULL);\n    vkDestroyImageView(dev->logical_device, dev->font_image_view, NULL);\n\n    free(dev->command_buffers);\n    nk_buffer_free(&dev->cmds);\n}\n\nNK_API\nvoid nk_sdl_shutdown(void) {\n    nk_font_atlas_clear(&sdl.atlas);\n    nk_free(&sdl.ctx);\n    nk_sdl_device_destroy();\n    memset(&sdl, 0, sizeof(sdl));\n}\n\nNK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas) {\n    nk_font_atlas_init_default(&sdl.atlas);\n    nk_font_atlas_begin(&sdl.atlas);\n    *atlas = &sdl.atlas;\n}\n\nNK_API void nk_sdl_font_stash_end(VkQueue graphics_queue) {\n    struct nk_sdl_device *dev = &sdl.vulkan;\n\n    const void *image;\n    int w, h;\n    image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_sdl_device_upload_atlas(graphics_queue, image, w, h);\n    nk_font_atlas_end(&sdl.atlas, nk_handle_ptr(dev->font_image_view),\n                      &dev->tex_null);\n    if (sdl.atlas.default_font) {\n        nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);\n    }\n}\n\nNK_API void nk_sdl_handle_grab(void) {\n    struct nk_context *ctx = &sdl.ctx;\n    if (ctx->input.mouse.grab) {\n        SDL_SetRelativeMouseMode(SDL_TRUE);\n    } else if (ctx->input.mouse.ungrab) {\n        /* better support for older SDL by setting mode first; causes an extra\n         * mouse motion event */\n        SDL_SetRelativeMouseMode(SDL_FALSE);\n        SDL_WarpMouseInWindow(sdl.win, (int)ctx->input.mouse.prev.x,\n                              (int)ctx->input.mouse.prev.y);\n    } else if (ctx->input.mouse.grabbed) {\n        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n    }\n}\n\nNK_API int nk_sdl_handle_event(SDL_Event *evt) {\n    struct nk_context *ctx = &sdl.ctx;\n    int ctrl_down = SDL_GetModState() & KMOD_CTRL;\n    static int insert_toggle = 0;\n\n    switch (evt->type) {\n    case SDL_KEYUP: /* KEYUP & KEYDOWN share same routine */\n    case SDL_KEYDOWN: {\n        int down = evt->type == SDL_KEYDOWN;\n        switch (evt->key.keysym.sym) {\n        case SDLK_RSHIFT: /* RSHIFT & LSHIFT share same routine */\n        case SDLK_LSHIFT:\n            nk_input_key(ctx, NK_KEY_SHIFT, down);\n            break;\n        case SDLK_DELETE:\n            nk_input_key(ctx, NK_KEY_DEL, down);\n            break;\n        case SDLK_RETURN:\n        case SDLK_KP_ENTER:\n            nk_input_key(ctx, NK_KEY_ENTER, down);\n            break;\n        case SDLK_TAB:\n            nk_input_key(ctx, NK_KEY_TAB, down);\n            break;\n        case SDLK_BACKSPACE:\n            nk_input_key(ctx, NK_KEY_BACKSPACE, down);\n            break;\n        case SDLK_HOME:\n            nk_input_key(ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_START, down);\n            break;\n        case SDLK_END:\n            nk_input_key(ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_END, down);\n            break;\n        case SDLK_PAGEDOWN:\n            nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);\n            break;\n        case SDLK_PAGEUP:\n            nk_input_key(ctx, NK_KEY_SCROLL_UP, down);\n            break;\n        case SDLK_z:\n            nk_input_key(ctx, NK_KEY_TEXT_UNDO,\n                         down && ctrl_down);\n            break;\n        case SDLK_r:\n            nk_input_key(ctx, NK_KEY_TEXT_REDO,\n                         down && ctrl_down);\n            break;\n        case SDLK_c:\n            nk_input_key(ctx, NK_KEY_COPY, down && ctrl_down);\n            break;\n        case SDLK_v:\n            nk_input_key(ctx, NK_KEY_PASTE, down && ctrl_down);\n            break;\n        case SDLK_x:\n            nk_input_key(ctx, NK_KEY_CUT, down && ctrl_down);\n            break;\n        case SDLK_b:\n            nk_input_key(ctx, NK_KEY_TEXT_LINE_START,\n                         down && ctrl_down);\n            break;\n        case SDLK_e:\n            nk_input_key(ctx, NK_KEY_TEXT_LINE_END,\n                         down && ctrl_down);\n            break;\n        case SDLK_UP:\n            nk_input_key(ctx, NK_KEY_UP, down);\n            break;\n        case SDLK_DOWN:\n            nk_input_key(ctx, NK_KEY_DOWN, down);\n            break;\n        case SDLK_ESCAPE:\n            nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down);\n            break;\n        case SDLK_INSERT:\n            if (down) insert_toggle = !insert_toggle;\n            if (insert_toggle) {\n                nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);\n            } else {\n                nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);\n            }\n            break;\n        case SDLK_a:\n            if(ctrl_down)\n                nk_input_key(ctx,NK_KEY_TEXT_SELECT_ALL, down);\n            break;\n        case SDLK_LEFT:\n            if (ctrl_down)\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else\n                nk_input_key(ctx, NK_KEY_LEFT, down);\n            break;\n        case SDLK_RIGHT:\n            if (ctrl_down)\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else\n                nk_input_key(ctx, NK_KEY_RIGHT, down);\n            break;\n        }\n        return 1;\n    }\n\n    case SDL_MOUSEBUTTONUP: /* MOUSEBUTTONUP & MOUSEBUTTONDOWN share same\n                               routine */\n    case SDL_MOUSEBUTTONDOWN: {\n        int down = evt->type == SDL_MOUSEBUTTONDOWN;\n        const int x = evt->button.x, y = evt->button.y;\n        switch (evt->button.button) {\n        case SDL_BUTTON_LEFT:\n            if (evt->button.clicks > 1)\n                nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);\n            nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);\n            break;\n        case SDL_BUTTON_MIDDLE:\n            nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);\n            break;\n        case SDL_BUTTON_RIGHT:\n            nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);\n            break;\n        case SDL_BUTTON_X1: nk_input_button(ctx, NK_BUTTON_X1, x, y, down); break;\n        case SDL_BUTTON_X2: nk_input_button(ctx, NK_BUTTON_X2, x, y, down); break;\n        }\n        return 1;\n    }\n\n    case SDL_MOUSEMOTION: {\n        if (ctx->input.mouse.grabbed) {\n            int x = (int)ctx->input.mouse.prev.x,\n                y = (int)ctx->input.mouse.prev.y;\n            nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);\n        } else\n            nk_input_motion(ctx, evt->motion.x, evt->motion.y);\n        return 1;\n    }\n\n    case SDL_TEXTINPUT: {\n        nk_glyph glyph;\n        memcpy(glyph, evt->text.text, NK_UTF_SIZE);\n        nk_input_glyph(ctx, glyph);\n        return 1;\n    }\n\n    case SDL_MOUSEWHEEL:\n        nk_input_scroll(ctx,nk_vec2(evt->wheel.preciseX, evt->wheel.preciseY));\n        return 1;\n    }\n    return 0;\n}\n\nNK_INTERN void update_texture_descriptor_set(\n    struct nk_sdl_device *dev,\n    struct nk_vulkan_texture_descriptor_set *texture_descriptor_set,\n    VkImageView image_view) {\n    VkDescriptorImageInfo descriptor_image_info;\n    VkWriteDescriptorSet descriptor_write;\n\n    texture_descriptor_set->image_view = image_view;\n\n    memset(&descriptor_image_info, 0, sizeof(VkDescriptorImageInfo));\n    descriptor_image_info.sampler = dev->sampler;\n    descriptor_image_info.imageView = texture_descriptor_set->image_view;\n    descriptor_image_info.imageLayout =\n        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n\n    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));\n    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n    descriptor_write.dstSet = texture_descriptor_set->descriptor_set;\n    descriptor_write.dstBinding = 0;\n    descriptor_write.dstArrayElement = 0;\n    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    descriptor_write.descriptorCount = 1;\n    descriptor_write.pImageInfo = &descriptor_image_info;\n\n    vkUpdateDescriptorSets(dev->logical_device, 1, &descriptor_write, 0, NULL);\n}\n\nNK_API\nVkSemaphore nk_sdl_render(VkQueue graphics_queue, uint32_t buffer_index,\n                          VkSemaphore wait_semaphore,\n                          enum nk_anti_aliasing AA) {\n    struct nk_sdl_device *dev = &sdl.vulkan;\n    struct nk_buffer vbuf, ebuf;\n\n    struct Mat4f projection = {\n        {2.0f, 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f,\n         0.0f, -1.0f, 1.0f, 0.0f, 1.0f},\n    };\n\n    VkCommandBufferBeginInfo begin_info;\n    VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 0.0f}}};\n    VkRenderPassBeginInfo render_pass_begin_nfo;\n    VkCommandBuffer command_buffer;\n    VkResult result;\n    VkViewport viewport;\n\n    VkDeviceSize doffset = 0;\n    VkImageView current_texture = NULL;\n    uint32_t index_offset = 0;\n    VkRect2D scissor;\n    uint32_t wait_semaphore_count;\n    VkSemaphore *wait_semaphores;\n    VkPipelineStageFlags wait_stage =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    VkSubmitInfo submit_info;\n    uint64_t time_now;\n\n    time_now = SDL_GetTicks64();\n    sdl.ctx.delta_time_seconds =\n        (float)(time_now - sdl.delta_time_milliseconds_last) / 1000.0f;\n    sdl.delta_time_milliseconds_last = time_now;\n\n    projection.m[0] /= sdl.display_width;\n    projection.m[5] /= sdl.display_height;\n\n    memcpy(dev->mapped_uniform, &projection, sizeof(projection));\n\n    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));\n    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n    memset(&render_pass_begin_nfo, 0, sizeof(VkRenderPassBeginInfo));\n    render_pass_begin_nfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;\n    render_pass_begin_nfo.renderPass = dev->render_pass;\n    render_pass_begin_nfo.renderArea.extent.width = (uint32_t)sdl.display_width;\n    render_pass_begin_nfo.renderArea.extent.height =\n        (uint32_t)sdl.display_height;\n    render_pass_begin_nfo.clearValueCount = 1;\n    render_pass_begin_nfo.pClearValues = &clear_value;\n    render_pass_begin_nfo.framebuffer = dev->framebuffers[buffer_index];\n\n    command_buffer = dev->command_buffers[buffer_index];\n\n    result = vkBeginCommandBuffer(command_buffer, &begin_info);\n    NK_ASSERT(result == VK_SUCCESS);\n    vkCmdBeginRenderPass(command_buffer, &render_pass_begin_nfo,\n                         VK_SUBPASS_CONTENTS_INLINE);\n\n    memset(&viewport, 0, sizeof(VkViewport));\n    viewport.width = (float)sdl.width;\n    viewport.height = (float)sdl.height;\n    viewport.maxDepth = 1.0f;\n    vkCmdSetViewport(command_buffer, 0, 1, &viewport);\n\n    vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                      dev->pipeline);\n    vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                            dev->pipeline_layout, 0, 1,\n                            &dev->uniform_descriptor_set, 0, NULL);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        /* load draw vertices & elements directly into vertex + element buffer\n         */\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] =\n                {{NK_VERTEX_POSITION, NK_FORMAT_FLOAT,\n                  NK_OFFSETOF(struct nk_sdl_vertex, position)},\n                 {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT,\n                  NK_OFFSETOF(struct nk_sdl_vertex, uv)},\n                 {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8,\n                  NK_OFFSETOF(struct nk_sdl_vertex, col)},\n                 {NK_VERTEX_LAYOUT_END}};\n            NK_MEMSET(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_sdl_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            nk_buffer_init_fixed(&vbuf, dev->mapped_vertex,\n                                 (size_t)dev->max_vertex_buffer);\n            nk_buffer_init_fixed(&ebuf, dev->mapped_index,\n                                 (size_t)dev->max_element_buffer);\n            nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n        }\n\n        /* iterate over and execute each draw command */\n\n        vkCmdBindVertexBuffers(command_buffer, 0, 1, &dev->vertex_buffer,\n                               &doffset);\n        vkCmdBindIndexBuffer(command_buffer, dev->index_buffer, 0,\n                             VK_INDEX_TYPE_UINT16);\n\n        nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) {\n            if (!cmd->texture.ptr) {\n                continue;\n            }\n            if (cmd->texture.ptr && cmd->texture.ptr != current_texture) {\n                int found = 0;\n                uint32_t i;\n                for (i = 0; i < dev->texture_descriptor_sets_len; i++) {\n                    if (dev->texture_descriptor_sets[i].image_view ==\n                        cmd->texture.ptr) {\n                        found = 1;\n                        break;\n                    }\n                }\n\n                if (!found) {\n                    update_texture_descriptor_set(\n                        dev, &dev->texture_descriptor_sets[i],\n                        (VkImageView)cmd->texture.ptr);\n                    dev->texture_descriptor_sets_len++;\n                }\n                vkCmdBindDescriptorSets(\n                    command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                    dev->pipeline_layout, 1, 1,\n                    &dev->texture_descriptor_sets[i].descriptor_set, 0, NULL);\n            }\n\n            if (!cmd->elem_count)\n                continue;\n\n            scissor.offset.x = (int32_t)(NK_MAX(cmd->clip_rect.x, 0.f));\n            scissor.offset.y = (int32_t)(NK_MAX(cmd->clip_rect.y, 0.f));\n            scissor.extent.width = (uint32_t)(cmd->clip_rect.w);\n            scissor.extent.height = (uint32_t)(cmd->clip_rect.h);\n            vkCmdSetScissor(command_buffer, 0, 1, &scissor);\n            vkCmdDrawIndexed(command_buffer, cmd->elem_count, 1, index_offset,\n                             0, 0);\n            index_offset += cmd->elem_count;\n        }\n        nk_clear(&sdl.ctx);\n    }\n\n    vkCmdEndRenderPass(command_buffer);\n    result = vkEndCommandBuffer(command_buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    if (wait_semaphore) {\n        wait_semaphore_count = 1;\n        wait_semaphores = &wait_semaphore;\n    } else {\n        wait_semaphore_count = 0;\n        wait_semaphores = NULL;\n    }\n\n    memset(&submit_info, 0, sizeof(VkSubmitInfo));\n    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n    submit_info.commandBufferCount = 1;\n    submit_info.pCommandBuffers = &command_buffer;\n    submit_info.pWaitDstStageMask = &wait_stage;\n    submit_info.waitSemaphoreCount = wait_semaphore_count;\n    submit_info.pWaitSemaphores = wait_semaphores;\n    submit_info.signalSemaphoreCount = 1;\n    submit_info.pSignalSemaphores = &dev->render_completed;\n\n    result = vkQueueSubmit(graphics_queue, 1, &submit_info, NULL);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    return dev->render_completed;\n}\n\nNK_INTERN void nk_sdl_clipboard_paste(nk_handle usr,\n                                      struct nk_text_edit *edit) {\n    const char *text = SDL_GetClipboardText();\n    if (text) {\n        nk_textedit_paste(edit, text, nk_strlen(text));\n        SDL_free((void *)text);\n    }\n    (void)usr;\n}\n\nNK_INTERN void nk_sdl_clipboard_copy(nk_handle usr, const char *text, int len) {\n    char *str = 0;\n    (void)usr;\n    if (!len)\n        return;\n    str = (char *)malloc((size_t)len + 1);\n    if (!str)\n        return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n    SDL_SetClipboardText(str);\n    free(str);\n}\n\nNK_API struct nk_context *\nnk_sdl_init(SDL_Window *win, VkDevice logical_device,\n            VkPhysicalDevice physical_device,\n            uint32_t graphics_queue_family_index, VkImageView *image_views,\n            uint32_t image_views_len, VkFormat color_format,\n            enum nk_sdl_init_state init_state, VkDeviceSize max_vertex_buffer,\n            VkDeviceSize max_element_buffer) {\n    (void)init_state;\n\n    memset(&sdl, 0, sizeof(struct nk_sdl));\n    sdl.win = win;\n\n    nk_init_default(&sdl.ctx, 0);\n    sdl.ctx.clip.copy = nk_sdl_clipboard_copy;\n    sdl.ctx.clip.paste = nk_sdl_clipboard_paste;\n    sdl.ctx.clip.userdata = nk_handle_ptr(0);\n\n    SDL_GetWindowSize(win, &sdl.width, &sdl.height);\n    SDL_Vulkan_GetDrawableSize(win, &sdl.display_width, &sdl.display_height);\n    nk_sdl_device_create(logical_device, physical_device,\n                         graphics_queue_family_index, image_views,\n                         image_views_len, color_format, max_vertex_buffer,\n                         max_element_buffer, (uint32_t)sdl.display_width,\n                         (uint32_t)sdl.display_height);\n\n    return &sdl.ctx;\n}\n\n#endif\n"
  },
  {
    "path": "demo/sdl_vulkan/shaders/demo.frag",
    "content": "#version 450\n#extension GL_ARB_separate_shader_objects : enable\n\nlayout(binding = 0) uniform sampler2D overlay;\n\nlayout(location = 0) in vec2 inUV;\n\nlayout(location = 0) out vec4 outColor;\n\nvoid main() {\n    outColor = texture(overlay, inUV);\n}\n"
  },
  {
    "path": "demo/sdl_vulkan/shaders/demo.vert",
    "content": "#version 450\n#extension GL_ARB_separate_shader_objects : enable\n\nlayout (location = 0) out vec2 outUV;\n\nvoid main()\n{\n    outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2);\n    gl_Position = vec4(outUV * 2.0f + -1.0f, 0.0f, 1.0f);\n}\n"
  },
  {
    "path": "demo/sdl_vulkan/src/Makefile",
    "content": "create_shader_inlined_header: nuklearshaders/nuklear.vert.spv nuklearshaders/nuklear.frag.spv\n\tawk -v st='// NUKLEAR_SHADERS_START' -v et='// NUKLEAR_SHADERS_END' -v repl=\"$$(xxd -i nuklearshaders/nuklear.vert.spv && xxd -i nuklearshaders/nuklear.frag.spv)\" '$$0 == st{del=1} $$0 == et{$$0 = repl; del=0} !del' nuklear_sdl_vulkan.in.h > nuklear_sdl_vulkan.h\n\nnuklearshaders/nuklear.vert.spv: nuklearshaders/nuklear.vert\n\tglslc --target-env=vulkan nuklearshaders/nuklear.vert -o nuklearshaders/nuklear.vert.spv\n\nnuklearshaders/nuklear.frag.spv: nuklearshaders/nuklear.frag\n\tglslc --target-env=vulkan nuklearshaders/nuklear.frag -o nuklearshaders/nuklear.frag.spv\n\nclean:\n\trm nuklearshaders/nuklear.vert.spv nuklearshaders/nuklear.frag.spv nuklear_sdl_vulkan.h\n"
  },
  {
    "path": "demo/sdl_vulkan/src/README.md",
    "content": "Contrary to OpenGL Vulkan needs precompiled shaders in the SPIR-V format which makes it a bit more difficult to inline the shadercode.\n\nAfter executing `make` the result should be a self contained `nuklear_sdl_vulkan.h`. Copy the result file to the parent directory and the \"release\" should be done.\n\nYou will need to have `xxd`, `glslc` and `awk` installed for this.\n"
  },
  {
    "path": "demo/sdl_vulkan/src/nuklear_sdl_vulkan.in.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warranty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_SDL_VULKAN_H_\n#define NK_SDL_VULKAN_H_\n\n// NUKLEAR_SHADERS_START\n// will be replaced with the real shader code\n// so we can have some ide support while editing the .in file\n#include \"nuklear.h\"\n\nunsigned char nuklearshaders_nuklear_vert_spv[] = {};\nunsigned int nuklearshaders_nuklear_vert_spv_len = 0;\nunsigned char nuklearshaders_nuklear_frag_spv[] = {};\nunsigned int nuklearshaders_nuklear_frag_spv_len = 0;\n// NUKLEAR_SHADERS_END\n\n#include <assert.h>\n#include <stddef.h>\n#include <string.h>\n#include <SDL2/SDL.h>\n\nenum nk_sdl_init_state { NK_SDL_DEFAULT = 0 };\n\nNK_API struct nk_context *\nnk_sdl_init(SDL_Window *win, VkDevice logical_device,\n            VkPhysicalDevice physical_device,\n            uint32_t graphics_queue_family_index, VkImageView *image_views,\n            uint32_t image_views_len, VkFormat color_format,\n            enum nk_sdl_init_state init_state, VkDeviceSize max_vertex_buffer,\n            VkDeviceSize max_element_buffer);\nNK_API void nk_sdl_shutdown(void);\nNK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void nk_sdl_font_stash_end(VkQueue graphics_queue);\nNK_API int nk_sdl_handle_event(SDL_Event *evt);\nNK_API VkSemaphore nk_sdl_render(VkQueue graphics_queue, uint32_t buffer_index,\n                                 VkSemaphore wait_semaphore,\n                                 enum nk_anti_aliasing AA);\nNK_API void nk_sdl_resize(uint32_t framebuffer_width,\n                          uint32_t framebuffer_height);\nNK_API void nk_sdl_device_destroy(void);\nNK_API void\nnk_sdl_device_create(VkDevice logical_device, VkPhysicalDevice physical_device,\n                     uint32_t graphics_queue_family_index,\n                     VkImageView *image_views, uint32_t image_views_len,\n                     VkFormat color_format, VkDeviceSize max_vertex_buffer,\n                     VkDeviceSize max_element_buffer,\n                     uint32_t framebuffer_width, uint32_t framebuffer_height);\nNK_API void nk_sdl_handle_grab(void);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_SDL_VULKAN_IMPLEMENTATION\n#undef NK_SDL_VULKAN_IMPLEMENTATION\n#include <stdlib.h>\n\n#ifndef NK_SDL_TEXT_MAX\n#define NK_SDL_TEXT_MAX 256\n#endif\n#ifndef NK_SDL_MAX_TEXTURES\n#define NK_SDL_MAX_TEXTURES 256\n#endif\n#ifndef NK_SDL_MAX_KEYS\n#define NK_SDL_MAX_KEYS 32\n#endif\n\n#define VK_COLOR_COMPONENT_MASK_RGBA                                           \\\n    VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |                      \\\n        VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT\n\nstruct nk_sdl_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstruct nk_vulkan_texture_descriptor_set {\n    VkImageView image_view;\n    VkDescriptorSet descriptor_set;\n};\n\nstruct nk_sdl_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    int max_vertex_buffer;\n    int max_element_buffer;\n    VkDevice logical_device;\n    VkPhysicalDevice physical_device;\n    VkImageView *image_views;\n    uint32_t image_views_len;\n    VkFormat color_format;\n    VkFramebuffer *framebuffers;\n    uint32_t framebuffers_len;\n    VkCommandBuffer *command_buffers;\n    uint32_t command_buffers_len;\n    VkSampler sampler;\n    VkCommandPool command_pool;\n    VkSemaphore render_completed;\n    VkBuffer vertex_buffer;\n    VkDeviceMemory vertex_memory;\n    void *mapped_vertex;\n    VkBuffer index_buffer;\n    VkDeviceMemory index_memory;\n    void *mapped_index;\n    VkBuffer uniform_buffer;\n    VkDeviceMemory uniform_memory;\n    void *mapped_uniform;\n    VkRenderPass render_pass;\n    VkDescriptorPool descriptor_pool;\n    VkDescriptorSetLayout uniform_descriptor_set_layout;\n    VkDescriptorSet uniform_descriptor_set;\n    VkDescriptorSetLayout texture_descriptor_set_layout;\n    struct nk_vulkan_texture_descriptor_set *texture_descriptor_sets;\n    uint32_t texture_descriptor_sets_len;\n    VkPipelineLayout pipeline_layout;\n    VkPipeline pipeline;\n    VkImage font_image;\n    VkImageView font_image_view;\n    VkDeviceMemory font_memory;\n};\n\nstatic struct nk_sdl {\n    SDL_Window *win;\n    int width, height;\n    int display_width, display_height;\n    struct nk_sdl_device vulkan;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    unsigned int text[NK_SDL_TEXT_MAX];\n    int text_len;\n    struct nk_vec2 scroll;\n    uint64_t delta_time_milliseconds_last;\n} sdl;\n\nstruct Mat4f {\n    float m[16];\n};\n\nNK_INTERN uint32_t nk_sdl_find_memory_index(VkPhysicalDevice physical_device,\n                                            uint32_t type_filter,\n                                            VkMemoryPropertyFlags properties) {\n    VkPhysicalDeviceMemoryProperties mem_properties;\n    uint32_t i;\n\n    vkGetPhysicalDeviceMemoryProperties(physical_device, &mem_properties);\n    for (i = 0; i < mem_properties.memoryTypeCount; i++) {\n        if ((type_filter & (1 << i)) &&\n            (mem_properties.memoryTypes[i].propertyFlags & properties) ==\n                properties) {\n            return i;\n        }\n    }\n\n    assert(0);\n    return 0;\n}\n\nNK_INTERN void nk_sdl_create_sampler(struct nk_sdl_device *dev) {\n    VkResult result;\n    VkSamplerCreateInfo sampler_info;\n    memset(&sampler_info, 0, sizeof(VkSamplerCreateInfo));\n\n    sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;\n    sampler_info.pNext = NULL;\n    sampler_info.maxAnisotropy = 1.0;\n    sampler_info.magFilter = VK_FILTER_LINEAR;\n    sampler_info.minFilter = VK_FILTER_LINEAR;\n    sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;\n    sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;\n    sampler_info.mipLodBias = 0.0f;\n    sampler_info.compareEnable = VK_FALSE;\n    sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;\n    sampler_info.minLod = 0.0f;\n    sampler_info.maxLod = 0.0f;\n    sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;\n\n    result = vkCreateSampler(dev->logical_device, &sampler_info, NULL,\n                             &dev->sampler);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_sdl_create_command_pool(struct nk_sdl_device *dev,\n                           uint32_t graphics_queue_family_index) {\n    VkResult result;\n    VkCommandPoolCreateInfo pool_info;\n    memset(&pool_info, 0, sizeof(VkCommandPoolCreateInfo));\n\n    pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;\n    pool_info.queueFamilyIndex = graphics_queue_family_index;\n    pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;\n    result = vkCreateCommandPool(dev->logical_device, &pool_info, NULL,\n                                 &dev->command_pool);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_sdl_create_command_buffers(struct nk_sdl_device *dev) {\n    VkResult result;\n    VkCommandBufferAllocateInfo allocate_info;\n    memset(&allocate_info, 0, sizeof(VkCommandBufferAllocateInfo));\n\n    dev->command_buffers = (VkCommandBuffer *)malloc(dev->image_views_len *\n                                                     sizeof(VkCommandBuffer));\n    dev->command_buffers_len = dev->image_views_len;\n\n    allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;\n    allocate_info.commandPool = dev->command_pool;\n    allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;\n    allocate_info.commandBufferCount = dev->command_buffers_len;\n\n    result = vkAllocateCommandBuffers(dev->logical_device, &allocate_info,\n                                      dev->command_buffers);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_sdl_create_semaphore(struct nk_sdl_device *dev) {\n    VkResult result;\n    VkSemaphoreCreateInfo semaphore_info;\n    memset(&semaphore_info, 0, sizeof(VkSemaphoreCreateInfo));\n\n    semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;\n    result = (vkCreateSemaphore(dev->logical_device, &semaphore_info, NULL,\n                                &dev->render_completed));\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_sdl_create_buffer_and_memory(struct nk_sdl_device *dev,\n                                               VkBuffer *buffer,\n                                               VkBufferUsageFlags usage,\n                                               VkDeviceMemory *memory,\n                                               VkDeviceSize size) {\n    VkMemoryRequirements mem_reqs;\n    VkResult result;\n    VkBufferCreateInfo buffer_info;\n    VkMemoryAllocateInfo alloc_info;\n\n    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));\n    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n    buffer_info.size = size;\n    buffer_info.usage = usage;\n    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    result = vkCreateBuffer(dev->logical_device, &buffer_info, NULL, buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkGetBufferMemoryRequirements(dev->logical_device, *buffer, &mem_reqs);\n\n    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n    alloc_info.allocationSize = mem_reqs.size;\n    alloc_info.memoryTypeIndex =\n        nk_sdl_find_memory_index(dev->physical_device, mem_reqs.memoryTypeBits,\n                                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n                                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\n    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL, memory);\n    NK_ASSERT(result == VK_SUCCESS);\n    result = vkBindBufferMemory(dev->logical_device, *buffer, *memory, 0);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_sdl_create_render_pass(struct nk_sdl_device *dev) {\n    VkAttachmentDescription attachment;\n    VkAttachmentReference color_reference;\n    VkSubpassDependency subpass_dependency;\n    VkSubpassDescription subpass_description;\n    VkRenderPassCreateInfo render_pass_info;\n    VkResult result;\n\n    memset(&attachment, 0, sizeof(VkAttachmentDescription));\n    attachment.format = dev->color_format;\n    attachment.samples = VK_SAMPLE_COUNT_1_BIT;\n    attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;\n    attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;\n    attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;\n    attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;\n    attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    attachment.finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n\n    memset(&color_reference, 0, sizeof(VkAttachmentReference));\n    color_reference.attachment = 0;\n    color_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;\n\n    memset(&subpass_dependency, 0, sizeof(VkSubpassDependency));\n    subpass_dependency.srcSubpass = VK_SUBPASS_EXTERNAL;\n    subpass_dependency.srcAccessMask = 0;\n    subpass_dependency.srcStageMask =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    subpass_dependency.dstSubpass = 0;\n    subpass_dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |\n                                       VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;\n    subpass_dependency.dstStageMask =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n\n    memset(&subpass_description, 0, sizeof(VkSubpassDescription));\n    subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;\n    subpass_description.colorAttachmentCount = 1;\n    subpass_description.pColorAttachments = &color_reference;\n\n    memset(&render_pass_info, 0, sizeof(VkRenderPassCreateInfo));\n    render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;\n    render_pass_info.attachmentCount = 1;\n    render_pass_info.pAttachments = &attachment;\n    render_pass_info.subpassCount = 1;\n    render_pass_info.pSubpasses = &subpass_description;\n    render_pass_info.dependencyCount = 1;\n    render_pass_info.pDependencies = &subpass_dependency;\n\n    result = vkCreateRenderPass(dev->logical_device, &render_pass_info, NULL,\n                                &dev->render_pass);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_sdl_create_framebuffers(struct nk_sdl_device *dev,\n                                          uint32_t framebuffer_width,\n                                          uint32_t framebuffer_height) {\n\n    VkFramebufferCreateInfo framebuffer_create_info;\n    uint32_t i;\n    VkResult result;\n\n    dev->framebuffers =\n        (VkFramebuffer *)malloc(dev->image_views_len * sizeof(VkFramebuffer));\n\n    memset(&framebuffer_create_info, 0, sizeof(VkFramebufferCreateInfo));\n    framebuffer_create_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;\n    framebuffer_create_info.renderPass = dev->render_pass;\n    framebuffer_create_info.attachmentCount = 1;\n    framebuffer_create_info.width = framebuffer_width;\n    framebuffer_create_info.height = framebuffer_height;\n    framebuffer_create_info.layers = 1;\n    for (i = 0; i < dev->image_views_len; i++) {\n        framebuffer_create_info.pAttachments = &dev->image_views[i];\n        result =\n            vkCreateFramebuffer(dev->logical_device, &framebuffer_create_info,\n                                NULL, &dev->framebuffers[i]);\n        NK_ASSERT(result == VK_SUCCESS);\n    }\n    dev->framebuffers_len = dev->image_views_len;\n}\n\nNK_INTERN void nk_sdl_create_descriptor_pool(struct nk_sdl_device *dev) {\n    VkDescriptorPoolSize pool_sizes[2];\n    VkDescriptorPoolCreateInfo pool_info;\n    VkResult result;\n\n    memset(&pool_sizes, 0, sizeof(VkDescriptorPoolSize) * 2);\n    pool_sizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n    pool_sizes[0].descriptorCount = 1;\n    pool_sizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    pool_sizes[1].descriptorCount = NK_SDL_MAX_TEXTURES;\n\n    memset(&pool_info, 0, sizeof(VkDescriptorPoolCreateInfo));\n    pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;\n    pool_info.poolSizeCount = 2;\n    pool_info.pPoolSizes = pool_sizes;\n    pool_info.maxSets = 1 + NK_SDL_MAX_TEXTURES;\n\n    result = vkCreateDescriptorPool(dev->logical_device, &pool_info, NULL,\n                                    &dev->descriptor_pool);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_sdl_create_uniform_descriptor_set_layout(struct nk_sdl_device *dev) {\n    VkDescriptorSetLayoutBinding binding;\n    VkDescriptorSetLayoutCreateInfo descriptor_set_info;\n    VkResult result;\n\n    memset(&binding, 0, sizeof(VkDescriptorSetLayoutBinding));\n    binding.binding = 0;\n    binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n    binding.descriptorCount = 1;\n    binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;\n\n    memset(&descriptor_set_info, 0, sizeof(VkDescriptorSetLayoutCreateInfo));\n    descriptor_set_info.sType =\n        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n    descriptor_set_info.bindingCount = 1;\n    descriptor_set_info.pBindings = &binding;\n\n    result =\n        vkCreateDescriptorSetLayout(dev->logical_device, &descriptor_set_info,\n                                    NULL, &dev->uniform_descriptor_set_layout);\n\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_sdl_create_and_update_uniform_descriptor_set(struct nk_sdl_device *dev) {\n    VkDescriptorSetAllocateInfo allocate_info;\n    VkDescriptorBufferInfo buffer_info;\n    VkWriteDescriptorSet descriptor_write;\n    VkResult result;\n\n    memset(&allocate_info, 0, sizeof(VkDescriptorSetAllocateInfo));\n    allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n    allocate_info.descriptorPool = dev->descriptor_pool;\n    allocate_info.descriptorSetCount = 1;\n    allocate_info.pSetLayouts = &dev->uniform_descriptor_set_layout;\n\n    result = vkAllocateDescriptorSets(dev->logical_device, &allocate_info,\n                                      &dev->uniform_descriptor_set);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&buffer_info, 0, sizeof(VkDescriptorBufferInfo));\n    buffer_info.buffer = dev->uniform_buffer;\n    buffer_info.offset = 0;\n    buffer_info.range = sizeof(struct Mat4f);\n\n    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));\n    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n    descriptor_write.dstSet = dev->uniform_descriptor_set;\n    descriptor_write.dstBinding = 0;\n    descriptor_write.dstArrayElement = 0;\n    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;\n    descriptor_write.descriptorCount = 1;\n    descriptor_write.pBufferInfo = &buffer_info;\n\n    vkUpdateDescriptorSets(dev->logical_device, 1, &descriptor_write, 0, NULL);\n}\n\nNK_INTERN void\nnk_sdl_create_texture_descriptor_set_layout(struct nk_sdl_device *dev) {\n    VkDescriptorSetLayoutBinding binding;\n    VkDescriptorSetLayoutCreateInfo descriptor_set_info;\n    VkResult result;\n\n    memset(&binding, 0, sizeof(VkDescriptorSetLayoutBinding));\n    binding.binding = 0;\n    binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    binding.descriptorCount = 1;\n    binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;\n\n    memset(&descriptor_set_info, 0, sizeof(VkDescriptorSetLayoutCreateInfo));\n    descriptor_set_info.sType =\n        VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;\n    descriptor_set_info.bindingCount = 1;\n    descriptor_set_info.pBindings = &binding;\n\n    result =\n        vkCreateDescriptorSetLayout(dev->logical_device, &descriptor_set_info,\n                                    NULL, &dev->texture_descriptor_set_layout);\n\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void\nnk_sdl_create_texture_descriptor_sets(struct nk_sdl_device *dev) {\n    VkDescriptorSetLayout *descriptor_set_layouts;\n    VkDescriptorSet *descriptor_sets;\n    VkDescriptorSetAllocateInfo allocate_info;\n    VkResult result;\n    int i;\n\n    descriptor_set_layouts = (VkDescriptorSetLayout *)malloc(\n        NK_SDL_MAX_TEXTURES * sizeof(VkDescriptorSetLayout));\n    descriptor_sets = (VkDescriptorSet *)malloc(NK_SDL_MAX_TEXTURES *\n                                                sizeof(VkDescriptorSet));\n\n    dev->texture_descriptor_sets =\n        (struct nk_vulkan_texture_descriptor_set *)malloc(\n            NK_SDL_MAX_TEXTURES *\n            sizeof(struct nk_vulkan_texture_descriptor_set));\n    dev->texture_descriptor_sets_len = 0;\n\n    for (i = 0; i < NK_SDL_MAX_TEXTURES; i++) {\n        descriptor_set_layouts[i] = dev->texture_descriptor_set_layout;\n        descriptor_sets[i] = dev->texture_descriptor_sets[i].descriptor_set;\n    }\n\n    memset(&allocate_info, 0, sizeof(VkDescriptorSetAllocateInfo));\n    allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;\n    allocate_info.descriptorPool = dev->descriptor_pool;\n    allocate_info.descriptorSetCount = NK_SDL_MAX_TEXTURES;\n    allocate_info.pSetLayouts = descriptor_set_layouts;\n\n    result = vkAllocateDescriptorSets(dev->logical_device, &allocate_info,\n                                      descriptor_sets);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    for (i = 0; i < NK_SDL_MAX_TEXTURES; i++) {\n        dev->texture_descriptor_sets[i].descriptor_set = descriptor_sets[i];\n    }\n    free(descriptor_set_layouts);\n    free(descriptor_sets);\n}\n\nNK_INTERN void nk_sdl_create_pipeline_layout(struct nk_sdl_device *dev) {\n    VkPipelineLayoutCreateInfo pipeline_layout_info;\n    VkDescriptorSetLayout descriptor_set_layouts[2];\n    VkResult result;\n\n    descriptor_set_layouts[0] = dev->uniform_descriptor_set_layout;\n    descriptor_set_layouts[1] = dev->texture_descriptor_set_layout;\n\n    memset(&pipeline_layout_info, 0, sizeof(VkPipelineLayoutCreateInfo));\n    pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;\n    pipeline_layout_info.setLayoutCount = 2;\n    pipeline_layout_info.pSetLayouts = descriptor_set_layouts;\n\n    result = (vkCreatePipelineLayout(dev->logical_device, &pipeline_layout_info,\n                                     NULL, &dev->pipeline_layout));\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN VkPipelineShaderStageCreateInfo\nnk_sdl_create_shader(struct nk_sdl_device *dev, unsigned char *spv_shader,\n                     uint32_t size, VkShaderStageFlagBits stage_bit) {\n    VkShaderModuleCreateInfo create_info;\n    VkPipelineShaderStageCreateInfo shader_info;\n    VkShaderModule module = NULL;\n    VkResult result;\n\n    memset(&create_info, 0, sizeof(VkShaderModuleCreateInfo));\n    create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;\n    create_info.codeSize = size;\n    create_info.pCode = (const uint32_t *)spv_shader;\n    result =\n        vkCreateShaderModule(dev->logical_device, &create_info, NULL, &module);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&shader_info, 0, sizeof(VkPipelineShaderStageCreateInfo));\n    shader_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;\n    shader_info.stage = stage_bit;\n    shader_info.module = module;\n    shader_info.pName = \"main\";\n    return shader_info;\n}\n\nNK_INTERN void nk_sdl_create_pipeline(struct nk_sdl_device *dev) {\n    VkPipelineInputAssemblyStateCreateInfo input_assembly_state;\n    VkPipelineRasterizationStateCreateInfo rasterization_state;\n    VkPipelineColorBlendAttachmentState attachment_state = {\n        VK_TRUE,\n        VK_BLEND_FACTOR_SRC_ALPHA,\n        VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,\n        VK_BLEND_OP_ADD,\n        VK_BLEND_FACTOR_SRC_ALPHA,\n        VK_BLEND_FACTOR_ONE,\n        VK_BLEND_OP_ADD,\n        VK_COLOR_COMPONENT_MASK_RGBA,\n    };\n    VkPipelineColorBlendStateCreateInfo color_blend_state;\n    VkPipelineViewportStateCreateInfo viewport_state;\n    VkPipelineMultisampleStateCreateInfo multisample_state;\n    VkDynamicState dynamic_states[2] = {VK_DYNAMIC_STATE_VIEWPORT,\n                                        VK_DYNAMIC_STATE_SCISSOR};\n    VkPipelineDynamicStateCreateInfo dynamic_state;\n    VkPipelineShaderStageCreateInfo shader_stages[2];\n    VkVertexInputBindingDescription vertex_input_info;\n    VkVertexInputAttributeDescription vertex_attribute_description[3];\n    VkPipelineVertexInputStateCreateInfo vertex_input;\n    VkGraphicsPipelineCreateInfo pipeline_info;\n    VkResult result;\n\n    memset(&input_assembly_state, 0,\n           sizeof(VkPipelineInputAssemblyStateCreateInfo));\n    input_assembly_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;\n    input_assembly_state.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;\n    input_assembly_state.primitiveRestartEnable = VK_FALSE;\n\n    memset(&rasterization_state, 0,\n           sizeof(VkPipelineRasterizationStateCreateInfo));\n    rasterization_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;\n    rasterization_state.polygonMode = VK_POLYGON_MODE_FILL;\n    rasterization_state.cullMode = VK_CULL_MODE_NONE;\n    rasterization_state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;\n    rasterization_state.lineWidth = 1.0f;\n\n    memset(&color_blend_state, 0, sizeof(VkPipelineColorBlendStateCreateInfo));\n    color_blend_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;\n    color_blend_state.attachmentCount = 1;\n    color_blend_state.pAttachments = &attachment_state;\n\n    memset(&viewport_state, 0, sizeof(VkPipelineViewportStateCreateInfo));\n    viewport_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;\n    viewport_state.viewportCount = 1;\n    viewport_state.scissorCount = 1;\n\n    memset(&multisample_state, 0, sizeof(VkPipelineMultisampleStateCreateInfo));\n    multisample_state.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;\n    multisample_state.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;\n\n    memset(&dynamic_state, 0, sizeof(VkPipelineDynamicStateCreateInfo));\n    dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;\n    dynamic_state.pDynamicStates = dynamic_states;\n    dynamic_state.dynamicStateCount = 2;\n\n    shader_stages[0] = nk_sdl_create_shader(\n        dev, nuklearshaders_nuklear_vert_spv,\n        nuklearshaders_nuklear_vert_spv_len, VK_SHADER_STAGE_VERTEX_BIT);\n    shader_stages[1] = nk_sdl_create_shader(\n        dev, nuklearshaders_nuklear_frag_spv,\n        nuklearshaders_nuklear_frag_spv_len, VK_SHADER_STAGE_FRAGMENT_BIT);\n\n    memset(&vertex_input_info, 0, sizeof(VkVertexInputBindingDescription));\n    vertex_input_info.binding = 0;\n    vertex_input_info.stride = sizeof(struct nk_sdl_vertex);\n    vertex_input_info.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;\n\n    memset(&vertex_attribute_description, 0,\n           sizeof(VkVertexInputAttributeDescription) * 3);\n    vertex_attribute_description[0].location = 0;\n    vertex_attribute_description[0].format = VK_FORMAT_R32G32_SFLOAT;\n    vertex_attribute_description[0].offset =\n        NK_OFFSETOF(struct nk_sdl_vertex, position);\n    vertex_attribute_description[1].location = 1;\n    vertex_attribute_description[1].format = VK_FORMAT_R32G32_SFLOAT;\n    vertex_attribute_description[1].offset =\n        NK_OFFSETOF(struct nk_sdl_vertex, uv);\n    vertex_attribute_description[2].location = 2;\n    vertex_attribute_description[2].format = VK_FORMAT_R8G8B8A8_UINT;\n    vertex_attribute_description[2].offset =\n        NK_OFFSETOF(struct nk_sdl_vertex, col);\n\n    memset(&vertex_input, 0, sizeof(VkPipelineVertexInputStateCreateInfo));\n    vertex_input.sType =\n        VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;\n    vertex_input.vertexBindingDescriptionCount = 1;\n    vertex_input.pVertexBindingDescriptions = &vertex_input_info;\n    vertex_input.vertexAttributeDescriptionCount = 3;\n    vertex_input.pVertexAttributeDescriptions = vertex_attribute_description;\n\n    memset(&pipeline_info, 0, sizeof(VkGraphicsPipelineCreateInfo));\n    pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;\n    pipeline_info.flags = 0;\n    pipeline_info.stageCount = 2;\n    pipeline_info.pStages = shader_stages;\n    pipeline_info.pVertexInputState = &vertex_input;\n    pipeline_info.pInputAssemblyState = &input_assembly_state;\n    pipeline_info.pViewportState = &viewport_state;\n    pipeline_info.pRasterizationState = &rasterization_state;\n    pipeline_info.pMultisampleState = &multisample_state;\n    pipeline_info.pColorBlendState = &color_blend_state;\n    pipeline_info.pDynamicState = &dynamic_state;\n    pipeline_info.layout = dev->pipeline_layout;\n    pipeline_info.renderPass = dev->render_pass;\n    pipeline_info.basePipelineIndex = -1;\n    pipeline_info.basePipelineHandle = NULL;\n\n    result = vkCreateGraphicsPipelines(dev->logical_device, NULL, 1,\n                                       &pipeline_info, NULL, &dev->pipeline);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkDestroyShaderModule(dev->logical_device, shader_stages[0].module, NULL);\n    vkDestroyShaderModule(dev->logical_device, shader_stages[1].module, NULL);\n}\n\nNK_INTERN void nk_sdl_create_render_resources(struct nk_sdl_device *dev,\n                                              uint32_t framebuffer_width,\n                                              uint32_t framebuffer_height) {\n    nk_sdl_create_render_pass(dev);\n    nk_sdl_create_framebuffers(dev, framebuffer_width, framebuffer_height);\n    nk_sdl_create_descriptor_pool(dev);\n    nk_sdl_create_uniform_descriptor_set_layout(dev);\n    nk_sdl_create_and_update_uniform_descriptor_set(dev);\n    nk_sdl_create_texture_descriptor_set_layout(dev);\n    nk_sdl_create_texture_descriptor_sets(dev);\n    nk_sdl_create_pipeline_layout(dev);\n    nk_sdl_create_pipeline(dev);\n}\n\nNK_API void\nnk_sdl_device_create(VkDevice logical_device, VkPhysicalDevice physical_device,\n                     uint32_t graphics_queue_family_index,\n                     VkImageView *image_views, uint32_t image_views_len,\n                     VkFormat color_format, VkDeviceSize max_vertex_buffer,\n                     VkDeviceSize max_element_buffer,\n                     uint32_t framebuffer_width, uint32_t framebuffer_height) {\n    struct nk_sdl_device *dev = &sdl.vulkan;\n    dev->max_vertex_buffer = max_vertex_buffer;\n    dev->max_element_buffer = max_element_buffer;\n    nk_buffer_init_default(&dev->cmds);\n    dev->logical_device = logical_device;\n    dev->physical_device = physical_device;\n    dev->image_views = image_views;\n    dev->image_views_len = image_views_len;\n    dev->color_format = color_format;\n    dev->framebuffers = NULL;\n    dev->framebuffers_len = 0;\n\n    nk_sdl_create_sampler(dev);\n    nk_sdl_create_command_pool(dev, graphics_queue_family_index);\n    nk_sdl_create_command_buffers(dev);\n    nk_sdl_create_semaphore(dev);\n\n    nk_sdl_create_buffer_and_memory(dev, &dev->vertex_buffer,\n                                    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,\n                                    &dev->vertex_memory, max_vertex_buffer);\n    nk_sdl_create_buffer_and_memory(dev, &dev->index_buffer,\n                                    VK_BUFFER_USAGE_INDEX_BUFFER_BIT,\n                                    &dev->index_memory, max_element_buffer);\n    nk_sdl_create_buffer_and_memory(dev, &dev->uniform_buffer,\n                                    VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,\n                                    &dev->uniform_memory, sizeof(struct Mat4f));\n\n    vkMapMemory(dev->logical_device, dev->vertex_memory, 0, max_vertex_buffer,\n                0, &dev->mapped_vertex);\n    vkMapMemory(dev->logical_device, dev->index_memory, 0, max_element_buffer,\n                0, &dev->mapped_index);\n    vkMapMemory(dev->logical_device, dev->uniform_memory, 0,\n                sizeof(struct Mat4f), 0, &dev->mapped_uniform);\n\n    nk_sdl_create_render_resources(dev, framebuffer_width, framebuffer_height);\n}\n\nNK_INTERN void nk_sdl_device_upload_atlas(VkQueue graphics_queue,\n                                          const void *image, int width,\n                                          int height) {\n    struct nk_sdl_device *dev = &sdl.vulkan;\n\n    VkImageCreateInfo image_info;\n    VkResult result;\n    VkMemoryRequirements mem_reqs;\n    VkMemoryAllocateInfo alloc_info;\n    VkBufferCreateInfo buffer_info;\n    uint8_t *data = 0;\n    VkCommandBufferBeginInfo begin_info;\n    VkCommandBuffer command_buffer;\n    VkImageMemoryBarrier image_memory_barrier;\n    VkBufferImageCopy buffer_copy_region;\n    VkImageMemoryBarrier image_shader_memory_barrier;\n    VkFence fence;\n    VkFenceCreateInfo fence_create;\n    VkSubmitInfo submit_info;\n    VkImageViewCreateInfo image_view_info;\n    struct {\n        VkDeviceMemory memory;\n        VkBuffer buffer;\n    } staging_buffer;\n\n    memset(&image_info, 0, sizeof(VkImageCreateInfo));\n    image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;\n    image_info.imageType = VK_IMAGE_TYPE_2D;\n    image_info.format = VK_FORMAT_R8G8B8A8_UNORM;\n    image_info.extent.width = (uint32_t)width;\n    image_info.extent.height = (uint32_t)height;\n    image_info.extent.depth = 1;\n    image_info.mipLevels = 1;\n    image_info.arrayLayers = 1;\n    image_info.samples = VK_SAMPLE_COUNT_1_BIT;\n    image_info.tiling = VK_IMAGE_TILING_OPTIMAL;\n    image_info.usage =\n        VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;\n    image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n    image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n\n    result =\n        vkCreateImage(dev->logical_device, &image_info, NULL, &dev->font_image);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkGetImageMemoryRequirements(dev->logical_device, dev->font_image,\n                                 &mem_reqs);\n\n    memset(&alloc_info, 0, sizeof(VkMemoryAllocateInfo));\n    alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;\n    alloc_info.allocationSize = mem_reqs.size;\n    alloc_info.memoryTypeIndex =\n        nk_sdl_find_memory_index(dev->physical_device, mem_reqs.memoryTypeBits,\n                                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);\n\n    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL,\n                              &dev->font_memory);\n    NK_ASSERT(result == VK_SUCCESS);\n    result = vkBindImageMemory(dev->logical_device, dev->font_image,\n                               dev->font_memory, 0);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&buffer_info, 0, sizeof(VkBufferCreateInfo));\n    buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;\n    buffer_info.size = alloc_info.allocationSize;\n    buffer_info.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;\n    buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;\n\n    result = vkCreateBuffer(dev->logical_device, &buffer_info, NULL,\n                            &staging_buffer.buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n    vkGetBufferMemoryRequirements(dev->logical_device, staging_buffer.buffer,\n                                  &mem_reqs);\n\n    alloc_info.allocationSize = mem_reqs.size;\n    alloc_info.memoryTypeIndex =\n        nk_sdl_find_memory_index(dev->physical_device, mem_reqs.memoryTypeBits,\n                                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |\n                                     VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);\n\n    result = vkAllocateMemory(dev->logical_device, &alloc_info, NULL,\n                              &staging_buffer.memory);\n    NK_ASSERT(result == VK_SUCCESS);\n    result = vkBindBufferMemory(dev->logical_device, staging_buffer.buffer,\n                                staging_buffer.memory, 0);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    result = vkMapMemory(dev->logical_device, staging_buffer.memory, 0,\n                         alloc_info.allocationSize, 0, (void **)&data);\n    NK_ASSERT(result == VK_SUCCESS);\n    memcpy(data, image, width * height * 4);\n    vkUnmapMemory(dev->logical_device, staging_buffer.memory);\n\n    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));\n    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n    NK_ASSERT(dev->command_buffers_len > 0);\n    /*\n    use the same command buffer as for render as we are regenerating the\n    buffer during render anyway\n    */\n    command_buffer = dev->command_buffers[0];\n    result = vkBeginCommandBuffer(command_buffer, &begin_info);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&image_memory_barrier, 0, sizeof(VkImageMemoryBarrier));\n    image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n    image_memory_barrier.image = dev->font_image;\n    image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;\n    image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n    image_memory_barrier.subresourceRange.aspectMask =\n        VK_IMAGE_ASPECT_COLOR_BIT;\n    image_memory_barrier.subresourceRange.levelCount = 1;\n    image_memory_barrier.subresourceRange.layerCount = 1;\n    image_memory_barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;\n\n    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,\n                         VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 1,\n                         &image_memory_barrier);\n\n    memset(&buffer_copy_region, 0, sizeof(VkBufferImageCopy));\n    buffer_copy_region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    buffer_copy_region.imageSubresource.layerCount = 1;\n    buffer_copy_region.imageExtent.width = (uint32_t)width;\n    buffer_copy_region.imageExtent.height = (uint32_t)height;\n    buffer_copy_region.imageExtent.depth = 1;\n\n    vkCmdCopyBufferToImage(\n        command_buffer, staging_buffer.buffer, dev->font_image,\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &buffer_copy_region);\n\n    memset(&image_shader_memory_barrier, 0, sizeof(VkImageMemoryBarrier));\n    image_shader_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;\n    image_shader_memory_barrier.image = dev->font_image;\n    image_shader_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_shader_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;\n    image_shader_memory_barrier.oldLayout =\n        VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;\n    image_shader_memory_barrier.newLayout =\n        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n    image_shader_memory_barrier.subresourceRange.aspectMask =\n        VK_IMAGE_ASPECT_COLOR_BIT;\n    image_shader_memory_barrier.subresourceRange.levelCount = 1;\n    image_shader_memory_barrier.subresourceRange.layerCount = 1;\n    image_shader_memory_barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,\n    image_shader_memory_barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT,\n\n    vkCmdPipelineBarrier(command_buffer, VK_PIPELINE_STAGE_TRANSFER_BIT,\n                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0,\n                         NULL, 1, &image_shader_memory_barrier);\n\n    result = vkEndCommandBuffer(command_buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&fence_create, 0, sizeof(VkFenceCreateInfo));\n    fence_create.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;\n\n    result = vkCreateFence(dev->logical_device, &fence_create, NULL, &fence);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    memset(&submit_info, 0, sizeof(VkSubmitInfo));\n    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n    submit_info.commandBufferCount = 1;\n    submit_info.pCommandBuffers = &command_buffer;\n\n    result = vkQueueSubmit(graphics_queue, 1, &submit_info, fence);\n    NK_ASSERT(result == VK_SUCCESS);\n    result =\n        vkWaitForFences(dev->logical_device, 1, &fence, VK_TRUE, UINT64_MAX);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    vkDestroyFence(dev->logical_device, fence, NULL);\n\n    vkFreeMemory(dev->logical_device, staging_buffer.memory, NULL);\n    vkDestroyBuffer(dev->logical_device, staging_buffer.buffer, NULL);\n\n    memset(&image_view_info, 0, sizeof(VkImageViewCreateInfo));\n    image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;\n    image_view_info.image = dev->font_image;\n    image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;\n    image_view_info.format = image_info.format;\n    image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;\n    image_view_info.subresourceRange.layerCount = 1;\n    image_view_info.subresourceRange.levelCount = 1;\n\n    result = vkCreateImageView(dev->logical_device, &image_view_info, NULL,\n                               &dev->font_image_view);\n    NK_ASSERT(result == VK_SUCCESS);\n}\n\nNK_INTERN void nk_sdl_destroy_render_resources(struct nk_sdl_device *dev) {\n    uint32_t i;\n\n    vkDestroyPipeline(dev->logical_device, dev->pipeline, NULL);\n    vkDestroyPipelineLayout(dev->logical_device, dev->pipeline_layout, NULL);\n    vkDestroyDescriptorSetLayout(dev->logical_device,\n                                 dev->texture_descriptor_set_layout, NULL);\n    vkDestroyDescriptorSetLayout(dev->logical_device,\n                                 dev->uniform_descriptor_set_layout, NULL);\n    vkDestroyDescriptorPool(dev->logical_device, dev->descriptor_pool, NULL);\n    for (i = 0; i < dev->framebuffers_len; i++) {\n        vkDestroyFramebuffer(dev->logical_device, dev->framebuffers[i], NULL);\n    }\n    free(dev->framebuffers);\n    dev->framebuffers_len = 0;\n    free(dev->texture_descriptor_sets);\n    dev->texture_descriptor_sets_len = 0;\n    vkDestroyRenderPass(dev->logical_device, dev->render_pass, NULL);\n}\n\nNK_API void nk_sdl_resize(uint32_t framebuffer_width,\n                          uint32_t framebuffer_height) {\n    struct nk_sdl_device *dev = &sdl.vulkan;\n\n    SDL_GetWindowSize(sdl.win, &sdl.width, &sdl.height);\n    sdl.display_width = framebuffer_width;\n    sdl.display_height = framebuffer_height;\n\n    nk_sdl_destroy_render_resources(dev);\n    nk_sdl_create_render_resources(dev, sdl.display_width, sdl.display_height);\n}\n\nNK_API void nk_sdl_device_destroy(void) {\n    struct nk_sdl_device *dev = &sdl.vulkan;\n\n    vkDeviceWaitIdle(dev->logical_device);\n\n    nk_sdl_destroy_render_resources(dev);\n\n    vkFreeCommandBuffers(dev->logical_device, dev->command_pool,\n                         dev->command_buffers_len, dev->command_buffers);\n    vkDestroyCommandPool(dev->logical_device, dev->command_pool, NULL);\n    vkDestroySemaphore(dev->logical_device, dev->render_completed, NULL);\n\n    vkUnmapMemory(dev->logical_device, dev->vertex_memory);\n    vkUnmapMemory(dev->logical_device, dev->index_memory);\n    vkUnmapMemory(dev->logical_device, dev->uniform_memory);\n\n    vkFreeMemory(dev->logical_device, dev->vertex_memory, NULL);\n    vkFreeMemory(dev->logical_device, dev->index_memory, NULL);\n    vkFreeMemory(dev->logical_device, dev->uniform_memory, NULL);\n\n    vkDestroyBuffer(dev->logical_device, dev->vertex_buffer, NULL);\n    vkDestroyBuffer(dev->logical_device, dev->index_buffer, NULL);\n    vkDestroyBuffer(dev->logical_device, dev->uniform_buffer, NULL);\n\n    vkDestroySampler(dev->logical_device, dev->sampler, NULL);\n\n    vkFreeMemory(dev->logical_device, dev->font_memory, NULL);\n    vkDestroyImage(dev->logical_device, dev->font_image, NULL);\n    vkDestroyImageView(dev->logical_device, dev->font_image_view, NULL);\n\n    free(dev->command_buffers);\n    nk_buffer_free(&dev->cmds);\n}\n\nNK_API\nvoid nk_sdl_shutdown(void) {\n    nk_font_atlas_clear(&sdl.atlas);\n    nk_free(&sdl.ctx);\n    nk_sdl_device_destroy();\n    memset(&sdl, 0, sizeof(sdl));\n}\n\nNK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas) {\n    nk_font_atlas_init_default(&sdl.atlas);\n    nk_font_atlas_begin(&sdl.atlas);\n    *atlas = &sdl.atlas;\n}\n\nNK_API void nk_sdl_font_stash_end(VkQueue graphics_queue) {\n    struct nk_sdl_device *dev = &sdl.vulkan;\n\n    const void *image;\n    int w, h;\n    image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_sdl_device_upload_atlas(graphics_queue, image, w, h);\n    nk_font_atlas_end(&sdl.atlas, nk_handle_ptr(dev->font_image_view),\n                      &dev->tex_null);\n    if (sdl.atlas.default_font) {\n        nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);\n    }\n}\n\nNK_API void nk_sdl_handle_grab(void) {\n    struct nk_context *ctx = &sdl.ctx;\n    if (ctx->input.mouse.grab) {\n        SDL_SetRelativeMouseMode(SDL_TRUE);\n    } else if (ctx->input.mouse.ungrab) {\n        /* better support for older SDL by setting mode first; causes an extra\n         * mouse motion event */\n        SDL_SetRelativeMouseMode(SDL_FALSE);\n        SDL_WarpMouseInWindow(sdl.win, (int)ctx->input.mouse.prev.x,\n                              (int)ctx->input.mouse.prev.y);\n    } else if (ctx->input.mouse.grabbed) {\n        ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n        ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n    }\n}\n\nNK_API int nk_sdl_handle_event(SDL_Event *evt) {\n    struct nk_context *ctx = &sdl.ctx;\n\n    switch (evt->type) {\n    case SDL_KEYUP: /* KEYUP & KEYDOWN share same routine */\n    case SDL_KEYDOWN: {\n        int down = evt->type == SDL_KEYDOWN;\n        const Uint8 *state = SDL_GetKeyboardState(0);\n        switch (evt->key.keysym.sym) {\n        case SDLK_RSHIFT: /* RSHIFT & LSHIFT share same routine */\n        case SDLK_LSHIFT:\n            nk_input_key(ctx, NK_KEY_SHIFT, down);\n            break;\n        case SDLK_DELETE:\n            nk_input_key(ctx, NK_KEY_DEL, down);\n            break;\n        case SDLK_RETURN:\n            nk_input_key(ctx, NK_KEY_ENTER, down);\n            break;\n        case SDLK_TAB:\n            nk_input_key(ctx, NK_KEY_TAB, down);\n            break;\n        case SDLK_BACKSPACE:\n            nk_input_key(ctx, NK_KEY_BACKSPACE, down);\n            break;\n        case SDLK_HOME:\n            nk_input_key(ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_START, down);\n            break;\n        case SDLK_END:\n            nk_input_key(ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_END, down);\n            break;\n        case SDLK_PAGEDOWN:\n            nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);\n            break;\n        case SDLK_PAGEUP:\n            nk_input_key(ctx, NK_KEY_SCROLL_UP, down);\n            break;\n        case SDLK_z:\n            nk_input_key(ctx, NK_KEY_TEXT_UNDO,\n                         down && state[SDL_SCANCODE_LCTRL]);\n            break;\n        case SDLK_r:\n            nk_input_key(ctx, NK_KEY_TEXT_REDO,\n                         down && state[SDL_SCANCODE_LCTRL]);\n            break;\n        case SDLK_c:\n            nk_input_key(ctx, NK_KEY_COPY, down && state[SDL_SCANCODE_LCTRL]);\n            break;\n        case SDLK_v:\n            nk_input_key(ctx, NK_KEY_PASTE, down && state[SDL_SCANCODE_LCTRL]);\n            break;\n        case SDLK_x:\n            nk_input_key(ctx, NK_KEY_CUT, down && state[SDL_SCANCODE_LCTRL]);\n            break;\n        case SDLK_b:\n            nk_input_key(ctx, NK_KEY_TEXT_LINE_START,\n                         down && state[SDL_SCANCODE_LCTRL]);\n            break;\n        case SDLK_e:\n            nk_input_key(ctx, NK_KEY_TEXT_LINE_END,\n                         down && state[SDL_SCANCODE_LCTRL]);\n            break;\n        case SDLK_UP:\n            nk_input_key(ctx, NK_KEY_UP, down);\n            break;\n        case SDLK_DOWN:\n            nk_input_key(ctx, NK_KEY_DOWN, down);\n            break;\n        case SDLK_LEFT:\n            if (state[SDL_SCANCODE_LCTRL])\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else\n                nk_input_key(ctx, NK_KEY_LEFT, down);\n            break;\n        case SDLK_RIGHT:\n            if (state[SDL_SCANCODE_LCTRL])\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else\n                nk_input_key(ctx, NK_KEY_RIGHT, down);\n            break;\n        }\n        return 1;\n    }\n\n    case SDL_MOUSEBUTTONUP: /* MOUSEBUTTONUP & MOUSEBUTTONDOWN share same\n                               routine */\n    case SDL_MOUSEBUTTONDOWN: {\n        int down = evt->type == SDL_MOUSEBUTTONDOWN;\n        const int x = evt->button.x, y = evt->button.y;\n        switch (evt->button.button) {\n        case SDL_BUTTON_LEFT:\n            if (evt->button.clicks > 1)\n                nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, down);\n            nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);\n            break;\n        case SDL_BUTTON_MIDDLE:\n            nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);\n            break;\n        case SDL_BUTTON_RIGHT:\n            nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);\n            break;\n        }\n        return 1;\n    }\n\n    case SDL_MOUSEMOTION: {\n        if (ctx->input.mouse.grabbed) {\n            int x = (int)ctx->input.mouse.prev.x,\n                y = (int)ctx->input.mouse.prev.y;\n            nk_input_motion(ctx, x + evt->motion.xrel, y + evt->motion.yrel);\n        } else\n            nk_input_motion(ctx, evt->motion.x, evt->motion.y);\n        return 1;\n    }\n\n    case SDL_TEXTINPUT: {\n        nk_glyph glyph;\n        memcpy(glyph, evt->text.text, NK_UTF_SIZE);\n        nk_input_glyph(ctx, glyph);\n        return 1;\n    }\n\n    case SDL_MOUSEWHEEL:\n        nk_input_scroll(ctx,nk_vec2(evt->wheel.preciseX, evt->wheel.preciseY));\n        return 1;\n    }\n    return 0;\n}\n\nNK_INTERN void update_texture_descriptor_set(\n    struct nk_sdl_device *dev,\n    struct nk_vulkan_texture_descriptor_set *texture_descriptor_set,\n    VkImageView image_view) {\n    VkDescriptorImageInfo descriptor_image_info;\n    VkWriteDescriptorSet descriptor_write;\n\n    texture_descriptor_set->image_view = image_view;\n\n    memset(&descriptor_image_info, 0, sizeof(VkDescriptorImageInfo));\n    descriptor_image_info.sampler = dev->sampler;\n    descriptor_image_info.imageView = texture_descriptor_set->image_view;\n    descriptor_image_info.imageLayout =\n        VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;\n\n    memset(&descriptor_write, 0, sizeof(VkWriteDescriptorSet));\n    descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;\n    descriptor_write.dstSet = texture_descriptor_set->descriptor_set;\n    descriptor_write.dstBinding = 0;\n    descriptor_write.dstArrayElement = 0;\n    descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;\n    descriptor_write.descriptorCount = 1;\n    descriptor_write.pImageInfo = &descriptor_image_info;\n\n    vkUpdateDescriptorSets(dev->logical_device, 1, &descriptor_write, 0, NULL);\n}\n\nNK_API\nVkSemaphore nk_sdl_render(VkQueue graphics_queue, uint32_t buffer_index,\n                          VkSemaphore wait_semaphore,\n                          enum nk_anti_aliasing AA) {\n    struct nk_sdl_device *dev = &sdl.vulkan;\n    struct nk_buffer vbuf, ebuf;\n\n    struct Mat4f projection = {\n        {2.0f, 0.0f, 0.0f, 0.0f, 0.0f, -2.0f, 0.0f, 0.0f, 0.0f, 0.0f, -1.0f,\n         0.0f, -1.0f, 1.0f, 0.0f, 1.0f},\n    };\n\n    VkCommandBufferBeginInfo begin_info;\n    VkClearValue clear_value = {{{0.0f, 0.0f, 0.0f, 0.0f}}};\n    VkRenderPassBeginInfo render_pass_begin_nfo;\n    VkCommandBuffer command_buffer;\n    VkResult result;\n    VkViewport viewport;\n\n    VkDeviceSize doffset = 0;\n    VkImageView current_texture = NULL;\n    uint32_t index_offset = 0;\n    VkRect2D scissor;\n    uint32_t wait_semaphore_count;\n    VkSemaphore *wait_semaphores;\n    VkPipelineStageFlags wait_stage =\n        VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;\n    VkSubmitInfo submit_info;\n    uint64_t time_now;\n\n    time_now = SDL_GetTicks64();\n    sdl.ctx.delta_time_seconds =\n        (float)(time_now - sdl.delta_time_milliseconds_last) / 1000.0f;\n    sdl.delta_time_milliseconds_last = time_now;\n\n    projection.m[0] /= sdl.display_width;\n    projection.m[5] /= sdl.display_height;\n\n    memcpy(dev->mapped_uniform, &projection, sizeof(projection));\n\n    memset(&begin_info, 0, sizeof(VkCommandBufferBeginInfo));\n    begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;\n\n    memset(&render_pass_begin_nfo, 0, sizeof(VkRenderPassBeginInfo));\n    render_pass_begin_nfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;\n    render_pass_begin_nfo.renderPass = dev->render_pass;\n    render_pass_begin_nfo.renderArea.extent.width = (uint32_t)sdl.display_width;\n    render_pass_begin_nfo.renderArea.extent.height =\n        (uint32_t)sdl.display_height;\n    render_pass_begin_nfo.clearValueCount = 1;\n    render_pass_begin_nfo.pClearValues = &clear_value;\n    render_pass_begin_nfo.framebuffer = dev->framebuffers[buffer_index];\n\n    command_buffer = dev->command_buffers[buffer_index];\n\n    result = vkBeginCommandBuffer(command_buffer, &begin_info);\n    NK_ASSERT(result == VK_SUCCESS);\n    vkCmdBeginRenderPass(command_buffer, &render_pass_begin_nfo,\n                         VK_SUBPASS_CONTENTS_INLINE);\n\n    memset(&viewport, 0, sizeof(VkViewport));\n    viewport.width = (float)sdl.width;\n    viewport.height = (float)sdl.height;\n    viewport.maxDepth = 1.0f;\n    vkCmdSetViewport(command_buffer, 0, 1, &viewport);\n\n    vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                      dev->pipeline);\n    vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                            dev->pipeline_layout, 0, 1,\n                            &dev->uniform_descriptor_set, 0, NULL);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        /* load draw vertices & elements directly into vertex + element buffer\n         */\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] =\n                {{NK_VERTEX_POSITION, NK_FORMAT_FLOAT,\n                  NK_OFFSETOF(struct nk_sdl_vertex, position)},\n                 {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT,\n                  NK_OFFSETOF(struct nk_sdl_vertex, uv)},\n                 {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8,\n                  NK_OFFSETOF(struct nk_sdl_vertex, col)},\n                 {NK_VERTEX_LAYOUT_END}};\n            NK_MEMSET(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_sdl_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_sdl_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            nk_buffer_init_fixed(&vbuf, dev->mapped_vertex,\n                                 (size_t)dev->max_vertex_buffer);\n            nk_buffer_init_fixed(&ebuf, dev->mapped_index,\n                                 (size_t)dev->max_element_buffer);\n            nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n        }\n\n        /* iterate over and execute each draw command */\n\n        vkCmdBindVertexBuffers(command_buffer, 0, 1, &dev->vertex_buffer,\n                               &doffset);\n        vkCmdBindIndexBuffer(command_buffer, dev->index_buffer, 0,\n                             VK_INDEX_TYPE_UINT16);\n\n        nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds) {\n            if (!cmd->texture.ptr) {\n                continue;\n            }\n            if (cmd->texture.ptr && cmd->texture.ptr != current_texture) {\n                int found = 0;\n                uint32_t i;\n                for (i = 0; i < dev->texture_descriptor_sets_len; i++) {\n                    if (dev->texture_descriptor_sets[i].image_view ==\n                        cmd->texture.ptr) {\n                        found = 1;\n                        break;\n                    }\n                }\n\n                if (!found) {\n                    update_texture_descriptor_set(\n                        dev, &dev->texture_descriptor_sets[i],\n                        (VkImageView)cmd->texture.ptr);\n                    dev->texture_descriptor_sets_len++;\n                }\n                vkCmdBindDescriptorSets(\n                    command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS,\n                    dev->pipeline_layout, 1, 1,\n                    &dev->texture_descriptor_sets[i].descriptor_set, 0, NULL);\n            }\n\n            if (!cmd->elem_count)\n                continue;\n\n            scissor.offset.x = (int32_t)(NK_MAX(cmd->clip_rect.x, 0.f));\n            scissor.offset.y = (int32_t)(NK_MAX(cmd->clip_rect.y, 0.f));\n            scissor.extent.width = (uint32_t)(cmd->clip_rect.w);\n            scissor.extent.height = (uint32_t)(cmd->clip_rect.h);\n            vkCmdSetScissor(command_buffer, 0, 1, &scissor);\n            vkCmdDrawIndexed(command_buffer, cmd->elem_count, 1, index_offset,\n                             0, 0);\n            index_offset += cmd->elem_count;\n        }\n        nk_clear(&sdl.ctx);\n    }\n\n    vkCmdEndRenderPass(command_buffer);\n    result = vkEndCommandBuffer(command_buffer);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    if (wait_semaphore) {\n        wait_semaphore_count = 1;\n        wait_semaphores = &wait_semaphore;\n    } else {\n        wait_semaphore_count = 0;\n        wait_semaphores = NULL;\n    }\n\n    memset(&submit_info, 0, sizeof(VkSubmitInfo));\n    submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;\n    submit_info.commandBufferCount = 1;\n    submit_info.pCommandBuffers = &command_buffer;\n    submit_info.pWaitDstStageMask = &wait_stage;\n    submit_info.waitSemaphoreCount = wait_semaphore_count;\n    submit_info.pWaitSemaphores = wait_semaphores;\n    submit_info.signalSemaphoreCount = 1;\n    submit_info.pSignalSemaphores = &dev->render_completed;\n\n    result = vkQueueSubmit(graphics_queue, 1, &submit_info, NULL);\n    NK_ASSERT(result == VK_SUCCESS);\n\n    return dev->render_completed;\n}\n\nNK_INTERN void nk_sdl_clipboard_paste(nk_handle usr,\n                                      struct nk_text_edit *edit) {\n    const char *text = SDL_GetClipboardText();\n    if (text) {\n        nk_textedit_paste(edit, text, nk_strlen(text));\n        SDL_free((void *)text);\n    }\n    (void)usr;\n}\n\nNK_INTERN void nk_sdl_clipboard_copy(nk_handle usr, const char *text, int len) {\n    char *str = 0;\n    (void)usr;\n    if (!len)\n        return;\n    str = (char *)malloc((size_t)len + 1);\n    if (!str)\n        return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n    SDL_SetClipboardText(str);\n    free(str);\n}\n\nNK_API struct nk_context *\nnk_sdl_init(SDL_Window *win, VkDevice logical_device,\n            VkPhysicalDevice physical_device,\n            uint32_t graphics_queue_family_index, VkImageView *image_views,\n            uint32_t image_views_len, VkFormat color_format,\n            enum nk_sdl_init_state init_state, VkDeviceSize max_vertex_buffer,\n            VkDeviceSize max_element_buffer) {\n    (void)init_state;\n\n    memset(&sdl, 0, sizeof(struct nk_sdl));\n    sdl.win = win;\n\n    nk_init_default(&sdl.ctx, 0);\n    sdl.ctx.clip.copy = nk_sdl_clipboard_copy;\n    sdl.ctx.clip.paste = nk_sdl_clipboard_paste;\n    sdl.ctx.clip.userdata = nk_handle_ptr(0);\n\n    SDL_GetWindowSize(win, &sdl.width, &sdl.height);\n    SDL_Vulkan_GetDrawableSize(win, &sdl.display_width, &sdl.display_height);\n    nk_sdl_device_create(logical_device, physical_device,\n                         graphics_queue_family_index, image_views,\n                         image_views_len, color_format, max_vertex_buffer,\n                         max_element_buffer, (uint32_t)sdl.display_width,\n                         (uint32_t)sdl.display_height);\n\n    return &sdl.ctx;\n}\n\n#endif\n"
  },
  {
    "path": "demo/sdl_vulkan/src/nuklearshaders/nuklear.frag",
    "content": "#version 450\n#extension GL_ARB_separate_shader_objects : enable\n\nlayout(binding = 0, set = 1) uniform sampler2D currentTexture;\n\nlayout(location = 0) in vec4 fragColor;\nlayout(location = 1) in vec2 fragUv;\nlayout(location = 0) out vec4 outColor;\n\nvoid main() {\n    vec4 texColor = texture(currentTexture, fragUv);\n    outColor = fragColor * texColor;\n}\n"
  },
  {
    "path": "demo/sdl_vulkan/src/nuklearshaders/nuklear.vert",
    "content": "#version 450\n#extension GL_ARB_separate_shader_objects : enable\n\nout gl_PerVertex {\n    vec4 gl_Position;\n};\n\nlayout(binding = 0) uniform UniformBufferObject {\n    mat4 projection;\n} ubo;\n\nlayout(location = 0) in vec2 position;\nlayout(location = 1) in vec2 uv;\nlayout(location = 2) in uvec4 color;\nlayout(location = 0) out vec4 fragColor;\nlayout(location = 1) out vec2 fragUv;\n\nvoid main() {\n    gl_Position = ubo.projection * vec4(position, 0.0, 1.0);\n    gl_Position.y = -gl_Position.y;\n    fragColor = vec4(color[0]/255.0, color[1]/255.0, color[2]/255.0, color[3]/255.0);\n    fragUv = uv;\n}\n"
  },
  {
    "path": "demo/sfml_opengl2/Makefile",
    "content": "# Install\nCC = g++\nBIN = demo\n\n# Flags\nCFLAGS += -s -Wall -Wextra -pedantic\n\nSRC = main.cpp\nOBJ = $(SRC:.cpp=.o)\n\nifeq ($(OS),Windows_NT)\n\t# Edit the line below to point to your SFML folder on Windows\n\tSFML_DIR = C:/Users/Ricky/MinGW-Libs/SFML\n\n\tBIN := $(BIN).exe\n\tLIBS = -lmingw32 -DSFML_STATIC -lsfml-window-s -lsfml-system-s -lopengl32 -lwinmm -lgdi32\nelse\n\t# Edit the line below to point to your SFML folder on Linux/MacOS\n\tSFML_DIR = /home/ricky/Libraries/SFML\n\n\tUNAME_S := $(shell uname -s)\n\tifeq ($(UNAME_S),Darwin)\n\t\tLIBS = -lsfml-window -lsfml-system -pthread -framework OpenGL\n\telse\n\t\tLIBS = -DSFML_STATIC -lsfml-window -lsfml-system -pthread -ludev -lGL -lX11 -lXrandr\n\tendif\nendif\n\nSFML_INC = -I $(SFML_DIR)/include\nSFML_LIB = -L $(SFML_DIR)/lib\n\n$(BIN):\n\t$(CC) $(SRC) $(CFLAGS) -o $(BIN) $(SFML_INC) $(SFML_LIB) $(LIBS)\n"
  },
  {
    "path": "demo/sfml_opengl2/Readme.md",
    "content": "# SFML 2.4 nuklear backend\n\nThis backend provides support for [SFML 2.4](http://www.sfml-dev.org). It will work on all platforms supported by SFML.\n\n## Compiling\n\nYou have to edit the Makefile provided so that you can build the demo. Edit the SFML_DIR variable to point to your SFML root folder. This will be the folder to which SFML was installed and contains the lib and include folders.\n\nOn Linux there is an extra step. You need to install the udev development files.\n"
  },
  {
    "path": "demo/sfml_opengl2/main.cpp",
    "content": "/* nuklear - v1.32.0 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <limits.h>\n#include <time.h>\n\n#include <SFML/OpenGL.hpp>\n#include <SFML/Window.hpp>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_SFML_GL2_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_sfml_gl2.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nint main(void)\n{\n    /* Platform */\n    sf::ContextSettings settings(24, 8, 4, 2, 2);\n    sf::Window win(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), \"Demo\", sf::Style::Default, settings);\n    win.setVerticalSyncEnabled(true);\n    win.setActive(true);\n    glViewport(0, 0, win.getSize().x, win.getSize().y);\n\n    /* GUI */\n    struct nk_context *ctx;\n    ctx = nk_sfml_init(&win);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    struct nk_font_atlas *atlas;\n    nk_sfml_font_stash_begin(&atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Roboto-Regular.ttf\", 14, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_sfml_font_stash_end();\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &droid->handle);*/\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    struct nk_colorf bg;\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (win.isOpen())\n    {\n        /* Input */\n        sf::Event evt;\n        nk_input_begin(ctx);\n        while(win.pollEvent(evt)) {\n            if(evt.type == sf::Event::Closed)\n                win.close();\n            else if(evt.type == sf::Event::Resized)\n                glViewport(0, 0, evt.size.width, evt.size.height);\n            nk_sfml_handle_event(&evt);\n        }\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        win.setActive(true);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(bg.r, bg.g, bg.b, bg.a);\n        /* IMPORTANT: `nk_sfml_render` modifies some global OpenGL state\n        * with blending, scissor, face culling and depth test and defaults everything\n        * back into a default state. Make sure to either save and restore or\n        * reset your own state after drawing rendering the UI. */\n        nk_sfml_render(NK_ANTI_ALIASING_ON);\n        win.display();\n    }\n    nk_sfml_shutdown();\n    return 0;\n}\n\n"
  },
  {
    "path": "demo/sfml_opengl2/nuklear_sfml_gl2.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_SFML_GL2_H_\n#define NK_SFML_GL2_H_\n\n#include <SFML/Window.hpp>\n#include <SFML/System/Clock.hpp>\n\nNK_API struct nk_context*   nk_sfml_init(sf::Window* window);\nNK_API void                 nk_sfml_font_stash_begin(struct nk_font_atlas** atlas);\nNK_API void                 nk_sfml_font_stash_end(void);\nNK_API int                  nk_sfml_handle_event(sf::Event* event);\nNK_API void                 nk_sfml_render(enum nk_anti_aliasing);\nNK_API void                 nk_sfml_shutdown(void);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n #ifdef NK_SFML_GL2_IMPLEMENTATION\n#include <cstdlib>\n#include <cstring>\n\nstruct nk_sfml_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint font_tex;\n};\n\nstruct nk_sfml_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstatic struct nk_sfml {\n    sf::Window* window;\n    struct nk_sfml_device ogl;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    sf::Clock* frame_delta_clock;\n} sfml;\n\nNK_INTERN void\nnk_sfml_device_upload_atlas(const void* image, int width, int height)\n{\n    struct nk_sfml_device* dev = &sfml.ogl;\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nNK_API void\nnk_sfml_render(enum nk_anti_aliasing AA)\n{\n    /* setup global state */\n    struct nk_sfml_device* dev = &sfml.ogl;\n\n    int window_width = sfml.window->getSize().x;\n    int window_height = sfml.window->getSize().y;\n\n    sfml.ctx.delta_time_seconds = (float)((double)sfml.frame_delta_clock->getElapsedTime().asMicroseconds() / 1000000);\n    sfml.frame_delta_clock->restart();\n\n    glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glEnable(GL_BLEND);\n    glEnable(GL_TEXTURE_2D);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n    glViewport(0, 0, (GLsizei)window_width, (GLsizei)window_height);\n    glMatrixMode(GL_TEXTURE);\n    glPushMatrix();\n    glLoadIdentity();\n    glMatrixMode(GL_PROJECTION);\n    glPushMatrix();\n    glLoadIdentity();\n    glOrtho(0.0f, window_width, window_height, 0.0f, -1.0f, 1.0f);\n    glMatrixMode(GL_MODELVIEW);\n    glPushMatrix();\n    glLoadIdentity();\n\n    glEnableClientState(GL_VERTEX_ARRAY);\n    glEnableClientState(GL_TEXTURE_COORD_ARRAY);\n    glEnableClientState(GL_COLOR_ARRAY);\n    {\n        GLsizei vs = sizeof(struct nk_sfml_vertex);\n        size_t vp = NK_OFFSETOF(struct nk_sfml_vertex, position);\n        size_t vt = NK_OFFSETOF(struct nk_sfml_vertex, uv);\n        size_t vc = NK_OFFSETOF(struct nk_sfml_vertex, col);\n\n        /* convert from command queue into draw  list and draw to screen */\n        const struct nk_draw_command* cmd;\n        const nk_draw_index* offset = NULL;\n        struct nk_buffer vbuf, ebuf;\n\n        /* fill converting configuration */\n        struct nk_convert_config config;\n        static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n            {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, position)},\n            {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, uv)},\n            {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sfml_vertex, col)},\n            {NK_VERTEX_LAYOUT_END}\n        };\n        memset(&config, 0, sizeof(config));\n        config.vertex_layout = vertex_layout;\n        config.vertex_size = sizeof(struct nk_sfml_vertex);\n        config.vertex_alignment = NK_ALIGNOF(struct nk_sfml_vertex);\n        config.tex_null = dev->tex_null;\n        config.circle_segment_count = 22;\n        config.curve_segment_count = 22;\n        config.arc_segment_count = 22;\n        config.global_alpha = 1.0f;\n        config.shape_AA = AA;\n        config.line_AA = AA;\n\n        /* convert shapes into vertices */\n        nk_buffer_init_default(&vbuf);\n        nk_buffer_init_default(&ebuf);\n        nk_convert(&sfml.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n\n        /* setup vertex buffer pointer */\n        const void* vertices = nk_buffer_memory_const(&vbuf);\n        glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp));\n        glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt));\n        glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));\n\n        /* iterate over and execute each draw command */\n        offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);\n        nk_draw_foreach(cmd, &sfml.ctx, &dev->cmds)\n        {\n            if(!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor(\n                (GLint)(cmd->clip_rect.x),\n                (GLint)((window_height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),\n                (GLint)(cmd->clip_rect.w),\n                (GLint)(cmd->clip_rect.h));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(&sfml.ctx);\n        nk_buffer_clear(&dev->cmds);\n        nk_buffer_free(&vbuf);\n        nk_buffer_free(&ebuf);\n    }\n\n    /* default OpenGL state */\n    glDisableClientState(GL_VERTEX_ARRAY);\n    glDisableClientState(GL_TEXTURE_COORD_ARRAY);\n    glDisableClientState(GL_COLOR_ARRAY);\n\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glDisable(GL_SCISSOR_TEST);\n    glDisable(GL_BLEND);\n    glDisable(GL_TEXTURE_2D);\n\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glMatrixMode(GL_TEXTURE);\n    glPopMatrix();\n    glMatrixMode(GL_MODELVIEW);\n    glPopMatrix();\n    glMatrixMode(GL_PROJECTION);\n    glPopMatrix();\n    glPopAttrib();\n}\n\nstatic void\nnk_sfml_clipboard_paste(nk_handle usr, struct nk_text_edit* edit)\n{\n#if 0\n    /* Not Implemented in SFML */\n    sf::Clipboard clipboard(sfml.window);\n    const char* text = clipboard.getText();\n\n    if(text)\n        nk_textedit_paste(edit, text, nk_strlen(text));\n        (void)usr;\n#else\n    NK_UNUSED(usr);\n    NK_UNUSED(edit);\n#endif\n}\n\nstatic void\nnk_sfml_clipboard_copy(nk_handle usr, const char* text, int len)\n{\n#if 0\n    char* str = 0;\n    (void)usr;\n    if(!len) return;\n    str = (char*)malloc((size_t)len+1);\n    if(!str) return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n\n    /* Not Implemented in SFML */\n    sf::Clipboard clipboard(sfml.window);\n    clipboard.setText(str);\n    free(str);\n#else\n    NK_UNUSED(usr);\n    NK_UNUSED(text);\n    NK_UNUSED(len);\n#endif\n}\n\nNK_API struct nk_context*\nnk_sfml_init(sf::Window* window)\n{\n    sfml.window = window;\n    nk_init_default(&sfml.ctx, 0);\n    sfml.ctx.clip.copy = nk_sfml_clipboard_copy;\n    sfml.ctx.clip.paste = nk_sfml_clipboard_paste;\n    sfml.ctx.clip.userdata = nk_handle_ptr(0);\n    nk_buffer_init_default(&sfml.ogl.cmds);\n    sfml.frame_delta_clock = new sf::Clock();\n    return &sfml.ctx;\n}\n\nNK_API void\nnk_sfml_font_stash_begin(struct nk_font_atlas** atlas)\n{\n    nk_font_atlas_init_default(&sfml.atlas);\n    nk_font_atlas_begin(&sfml.atlas);\n    *atlas = &sfml.atlas;\n}\n\nNK_API void\nnk_sfml_font_stash_end()\n{\n    int w, h;\n    const void* img;\n    img = nk_font_atlas_bake(&sfml.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_sfml_device_upload_atlas(img, w, h);\n    nk_font_atlas_end(&sfml.atlas, nk_handle_id((int)sfml.ogl.font_tex), &sfml.ogl.tex_null);\n    if(sfml.atlas.default_font)\n        nk_style_set_font(&sfml.ctx, &sfml.atlas.default_font->handle);\n}\n\nNK_API int\nnk_sfml_handle_event(sf::Event* evt)\n{\n    struct nk_context* ctx = &sfml.ctx;\n    /* optional grabbing behavior */\n    if(ctx->input.mouse.grab)\n        ctx->input.mouse.grab = 0;\n    else if(ctx->input.mouse.ungrab) {\n        int x = (int)ctx->input.mouse.prev.x;\n        int y = (int)ctx->input.mouse.prev.y;\n        sf::Mouse::setPosition(sf::Vector2i(x, y), *sfml.window);\n        ctx->input.mouse.ungrab = 0;\n    }\n    if(evt->type == sf::Event::KeyReleased || evt->type == sf::Event::KeyPressed)\n    {\n        int down = evt->type == sf::Event::KeyPressed;\n        sf::Keyboard::Key key = evt->key.code;\n        if(key == sf::Keyboard::RShift || key == sf::Keyboard::LShift)\n            nk_input_key(ctx, NK_KEY_SHIFT, down);\n        else if(key == sf::Keyboard::Delete)\n            nk_input_key(ctx, NK_KEY_DEL, down);\n        else if(key == sf::Keyboard::Enter)\n            nk_input_key(ctx, NK_KEY_ENTER, down);\n        else if(key == sf::Keyboard::Tab)\n            nk_input_key(ctx, NK_KEY_TAB, down);\n        else if(key == sf::Keyboard::BackSpace)\n            nk_input_key(ctx, NK_KEY_BACKSPACE, down);\n        else if(key == sf::Keyboard::Home) {\n            nk_input_key(ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_START, down);\n        } else if(key == sf::Keyboard::End) {\n            nk_input_key(ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_END, down);\n        } else if(key == sf::Keyboard::PageDown)\n            nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);\n        else if(key == sf::Keyboard::PageUp)\n            nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);\n        else if(key == sf::Keyboard::Z)\n            nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::R)\n            nk_input_key(ctx, NK_KEY_TEXT_REDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::C)\n            nk_input_key(ctx, NK_KEY_COPY, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::V)\n            nk_input_key(ctx, NK_KEY_PASTE, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::X)\n            nk_input_key(ctx, NK_KEY_CUT, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::B)\n            nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::E)\n            nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::Up)\n            nk_input_key(ctx, NK_KEY_UP, down);\n        else if(key == sf::Keyboard::Down)\n            nk_input_key(ctx, NK_KEY_DOWN, down);\n        else if(key == sf::Keyboard::Left) {\n            if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else nk_input_key(ctx, NK_KEY_LEFT, down);\n        } else if(key == sf::Keyboard::Right) {\n            if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else nk_input_key(ctx, NK_KEY_RIGHT, down);\n        } else return 0;\n        return 1;\n    } else if(evt->type == sf::Event::MouseButtonPressed || evt->type == sf::Event::MouseButtonReleased) {\n        int down = evt->type == sf::Event::MouseButtonPressed;\n        const int x = evt->mouseButton.x, y = evt->mouseButton.y;\n        if(evt->mouseButton.button == sf::Mouse::Left)\n            nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);\n        if(evt->mouseButton.button == sf::Mouse::Middle)\n            nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);\n        if(evt->mouseButton.button == sf::Mouse::Right)\n            nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);\n        if(evt->mouseButton.button == sf::Mouse::XButton1)\n            nk_input_button(ctx, NK_BUTTON_X1, x, y, down);\n        if(evt->mouseButton.button == sf::Mouse::XButton2)\n            nk_input_button(ctx, NK_BUTTON_X2, x, y, down);\n        else return 0;\n        return 1;\n    } else if(evt->type == sf::Event::MouseMoved) {\n        nk_input_motion(ctx, evt->mouseMove.x, evt->mouseMove.y);\n        return 1;\n    } else if(evt->type == sf::Event::TouchBegan || evt->type == sf::Event::TouchEnded) {\n        int down = evt->type == sf::Event::TouchBegan;\n        const int x = evt->touch.x, y = evt->touch.y;\n        ctx->input.mouse.pos.x = x;\n        ctx->input.mouse.pos.y = y;\n        nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);\n        return 1;\n    } else if(evt->type == sf::Event::TouchMoved) {\n        if(ctx->input.mouse.grabbed) {\n            int x = (int)ctx->input.mouse.prev.x;\n            int y = (int)ctx->input.mouse.prev.y;\n            nk_input_motion(ctx, x + evt->touch.x, y + evt->touch.y);\n        } else nk_input_motion(ctx, evt->touch.x, evt->touch.y);\n        return 1;\n    } else if(evt->type == sf::Event::TextEntered) {\n        nk_input_unicode(ctx, evt->text.unicode);\n        return 1;\n    } else if(evt->type == sf::Event::MouseWheelScrolled) {\n        nk_input_scroll(ctx, nk_vec2(0,evt->mouseWheelScroll.delta));\n        return 1;\n    }\n    return 0;\n}\n\nNK_API\nvoid nk_sfml_shutdown(void)\n{\n    struct nk_sfml_device* dev = &sfml.ogl;\n    nk_font_atlas_clear(&sfml.atlas);\n    nk_free(&sfml.ctx);\n    glDeleteTextures(1, &dev->font_tex);\n    nk_buffer_free(&dev->cmds);\n    delete sfml.frame_delta_clock;\n    memset(&sfml, 0, sizeof(sfml));\n}\n\n#endif\n"
  },
  {
    "path": "demo/sfml_opengl3/Makefile",
    "content": "# Install\nCC = g++\nBIN = demo\n\n# Flags\nCFLAGS += -s -Wall -Wextra -pedantic\n\nSRC = main.cpp\nOBJ = $(SRC:.cpp=.o)\n\nifeq ($(OS),Windows_NT)\n\t# Edit the line below to point to your SFML/GLAD folder on Windows\n\tSFML_DIR = C:/Users/Ricky/MinGW-Libs/SFML\n\tGLAD_DIR = C:/Users/Ricky/MinGW-Libs/GLAD\n\n\tBIN := $(BIN).exe\n\tLIBS = -lmingw32 -DSFML_STATIC -lsfml-window-s -lsfml-system-s -lopengl32 -lwinmm -lgdi32\nelse\n\t# Edit the line below to point to your SFML/GLAD folder on Linux/MacOS\n\tSFML_DIR = /home/ricky/Libraries/SFML\n\tGLAD_DIR = /home/ricky/Libraries/GLAD\n\n\tUNAME_S := $(shell uname -s)\n\tifeq ($(UNAME_S),Darwin)\n\t\tLIBS = -lsfml-window -lsfml-system -pthread -framework OpenGL\n\telse\n\t\tLIBS = -DSFML_STATIC -lsfml-window-s -lsfml-system-s -pthread -ludev -lGL -lX11 -lXrandr\n\tendif\nendif\n\nSFML_INC = -I $(SFML_DIR)/include\nSFML_LIB = -L $(SFML_DIR)/lib\nGLAD_INC = -I $(GLAD_DIR)/include\nGLAD_SRC = $(GLAD_DIR)/src/glad.c\n\n$(BIN):\n\t$(CC) $(GLAD_SRC) $(SRC) $(CFLAGS) $(GLAD_INC) $(SFML_INC) $(SFML_LIB) $(SFML_EXT) -o $(BIN) $(LIBS)\n"
  },
  {
    "path": "demo/sfml_opengl3/Readme.md",
    "content": "# SFML 2.4 nuklear backend\n\nThis backend provides support for [SFML 2.4](http://www.sfml-dev.org). It will work on all platforms supported by SFML.\n\n## Compiling\n\nThis backend uses Glad to handle OpenGL extensions. You can download the Glad files used to test this backend from [this link](http://glad.dav1d.de/#profile=compatibility&api=gl%3D3.2&api=gles1%3Dnone&api=gles2%3D3.2&api=glsc2%3Dnone&extensions=GL_3DFX_multisample&extensions=GL_3DFX_tbuffer&extensions=GL_3DFX_texture_compression_FXT1&extensions=GL_AMD_blend_minmax_factor&extensions=GL_AMD_compressed_3DC_texture&extensions=GL_AMD_compressed_ATC_texture&extensions=GL_AMD_conservative_depth&extensions=GL_AMD_debug_output&extensions=GL_AMD_depth_clamp_separate&extensions=GL_AMD_draw_buffers_blend&extensions=GL_AMD_gcn_shader&extensions=GL_AMD_gpu_shader_half_float&extensions=GL_AMD_gpu_shader_int64&extensions=GL_AMD_interleaved_elements&extensions=GL_AMD_multi_draw_indirect&extensions=GL_AMD_name_gen_delete&extensions=GL_AMD_occlusion_query_event&extensions=GL_AMD_performance_monitor&extensions=GL_AMD_pinned_memory&extensions=GL_AMD_program_binary_Z400&extensions=GL_AMD_query_buffer_object&extensions=GL_AMD_sample_positions&extensions=GL_AMD_seamless_cubemap_per_texture&extensions=GL_AMD_shader_atomic_counter_ops&extensions=GL_AMD_shader_ballot&extensions=GL_AMD_shader_explicit_vertex_parameter&extensions=GL_AMD_shader_stencil_export&extensions=GL_AMD_shader_trinary_minmax&extensions=GL_AMD_sparse_texture&extensions=GL_AMD_stencil_operation_extended&extensions=GL_AMD_texture_texture4&extensions=GL_AMD_transform_feedback3_lines_triangles&extensions=GL_AMD_transform_feedback4&extensions=GL_AMD_vertex_shader_layer&extensions=GL_AMD_vertex_shader_tessellator&extensions=GL_AMD_vertex_shader_viewport_index&extensions=GL_ANDROID_extension_pack_es31a&extensions=GL_ANGLE_depth_texture&extensions=GL_ANGLE_framebuffer_blit&extensions=GL_ANGLE_framebuffer_multisample&extensions=GL_ANGLE_instanced_arrays&extensions=GL_ANGLE_pack_reverse_row_order&extensions=GL_ANGLE_program_binary&extensions=GL_ANGLE_texture_compression_dxt3&extensions=GL_ANGLE_texture_compression_dxt5&extensions=GL_ANGLE_texture_usage&extensions=GL_ANGLE_translated_shader_source&extensions=GL_APPLE_aux_depth_stencil&extensions=GL_APPLE_client_storage&extensions=GL_APPLE_clip_distance&extensions=GL_APPLE_color_buffer_packed_float&extensions=GL_APPLE_copy_texture_levels&extensions=GL_APPLE_element_array&extensions=GL_APPLE_fence&extensions=GL_APPLE_float_pixels&extensions=GL_APPLE_flush_buffer_range&extensions=GL_APPLE_framebuffer_multisample&extensions=GL_APPLE_object_purgeable&extensions=GL_APPLE_rgb_422&extensions=GL_APPLE_row_bytes&extensions=GL_APPLE_specular_vector&extensions=GL_APPLE_sync&extensions=GL_APPLE_texture_format_BGRA8888&extensions=GL_APPLE_texture_max_level&extensions=GL_APPLE_texture_packed_float&extensions=GL_APPLE_texture_range&extensions=GL_APPLE_transform_hint&extensions=GL_APPLE_vertex_array_object&extensions=GL_APPLE_vertex_array_range&extensions=GL_APPLE_vertex_program_evaluators&extensions=GL_APPLE_ycbcr_422&extensions=GL_ARB_ES2_compatibility&extensions=GL_ARB_ES3_1_compatibility&extensions=GL_ARB_ES3_2_compatibility&extensions=GL_ARB_ES3_compatibility&extensions=GL_ARB_arrays_of_arrays&extensions=GL_ARB_base_instance&extensions=GL_ARB_bindless_texture&extensions=GL_ARB_blend_func_extended&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_cl_event&extensions=GL_ARB_clear_buffer_object&extensions=GL_ARB_clear_texture&extensions=GL_ARB_clip_control&extensions=GL_ARB_color_buffer_float&extensions=GL_ARB_compatibility&extensions=GL_ARB_compressed_texture_pixel_storage&extensions=GL_ARB_compute_shader&extensions=GL_ARB_compute_variable_group_size&extensions=GL_ARB_conditional_render_inverted&extensions=GL_ARB_conservative_depth&extensions=GL_ARB_copy_buffer&extensions=GL_ARB_copy_image&extensions=GL_ARB_cull_distance&extensions=GL_ARB_debug_output&extensions=GL_ARB_depth_buffer_float&extensions=GL_ARB_depth_clamp&extensions=GL_ARB_depth_texture&extensions=GL_ARB_derivative_control&extensions=GL_ARB_direct_state_access&extensions=GL_ARB_draw_buffers&extensions=GL_ARB_draw_buffers_blend&extensions=GL_ARB_draw_elements_base_vertex&extensions=GL_ARB_draw_indirect&extensions=GL_ARB_draw_instanced&extensions=GL_ARB_enhanced_layouts&extensions=GL_ARB_explicit_attrib_location&extensions=GL_ARB_explicit_uniform_location&extensions=GL_ARB_fragment_coord_conventions&extensions=GL_ARB_fragment_layer_viewport&extensions=GL_ARB_fragment_program&extensions=GL_ARB_fragment_program_shadow&extensions=GL_ARB_fragment_shader&extensions=GL_ARB_fragment_shader_interlock&extensions=GL_ARB_framebuffer_no_attachments&extensions=GL_ARB_framebuffer_object&extensions=GL_ARB_framebuffer_sRGB&extensions=GL_ARB_geometry_shader4&extensions=GL_ARB_get_program_binary&extensions=GL_ARB_get_texture_sub_image&extensions=GL_ARB_gpu_shader5&extensions=GL_ARB_gpu_shader_fp64&extensions=GL_ARB_gpu_shader_int64&extensions=GL_ARB_half_float_pixel&extensions=GL_ARB_half_float_vertex&extensions=GL_ARB_imaging&extensions=GL_ARB_indirect_parameters&extensions=GL_ARB_instanced_arrays&extensions=GL_ARB_internalformat_query&extensions=GL_ARB_internalformat_query2&extensions=GL_ARB_invalidate_subdata&extensions=GL_ARB_map_buffer_alignment&extensions=GL_ARB_map_buffer_range&extensions=GL_ARB_matrix_palette&extensions=GL_ARB_multi_bind&extensions=GL_ARB_multi_draw_indirect&extensions=GL_ARB_multisample&extensions=GL_ARB_multitexture&extensions=GL_ARB_occlusion_query&extensions=GL_ARB_occlusion_query2&extensions=GL_ARB_parallel_shader_compile&extensions=GL_ARB_pipeline_statistics_query&extensions=GL_ARB_pixel_buffer_object&extensions=GL_ARB_point_parameters&extensions=GL_ARB_point_sprite&extensions=GL_ARB_post_depth_coverage&extensions=GL_ARB_program_interface_query&extensions=GL_ARB_provoking_vertex&extensions=GL_ARB_query_buffer_object&extensions=GL_ARB_robust_buffer_access_behavior&extensions=GL_ARB_robustness&extensions=GL_ARB_robustness_isolation&extensions=GL_ARB_sample_locations&extensions=GL_ARB_sample_shading&extensions=GL_ARB_sampler_objects&extensions=GL_ARB_seamless_cube_map&extensions=GL_ARB_seamless_cubemap_per_texture&extensions=GL_ARB_separate_shader_objects&extensions=GL_ARB_shader_atomic_counter_ops&extensions=GL_ARB_shader_atomic_counters&extensions=GL_ARB_shader_ballot&extensions=GL_ARB_shader_bit_encoding&extensions=GL_ARB_shader_clock&extensions=GL_ARB_shader_draw_parameters&extensions=GL_ARB_shader_group_vote&extensions=GL_ARB_shader_image_load_store&extensions=GL_ARB_shader_image_size&extensions=GL_ARB_shader_objects&extensions=GL_ARB_shader_precision&extensions=GL_ARB_shader_stencil_export&extensions=GL_ARB_shader_storage_buffer_object&extensions=GL_ARB_shader_subroutine&extensions=GL_ARB_shader_texture_image_samples&extensions=GL_ARB_shader_texture_lod&extensions=GL_ARB_shader_viewport_layer_array&extensions=GL_ARB_shading_language_100&extensions=GL_ARB_shading_language_420pack&extensions=GL_ARB_shading_language_include&extensions=GL_ARB_shading_language_packing&extensions=GL_ARB_shadow&extensions=GL_ARB_shadow_ambient&extensions=GL_ARB_sparse_buffer&extensions=GL_ARB_sparse_texture&extensions=GL_ARB_sparse_texture2&extensions=GL_ARB_sparse_texture_clamp&extensions=GL_ARB_stencil_texturing&extensions=GL_ARB_sync&extensions=GL_ARB_tessellation_shader&extensions=GL_ARB_texture_barrier&extensions=GL_ARB_texture_border_clamp&extensions=GL_ARB_texture_buffer_object&extensions=GL_ARB_texture_buffer_object_rgb32&extensions=GL_ARB_texture_buffer_range&extensions=GL_ARB_texture_compression&extensions=GL_ARB_texture_compression_bptc&extensions=GL_ARB_texture_compression_rgtc&extensions=GL_ARB_texture_cube_map&extensions=GL_ARB_texture_cube_map_array&extensions=GL_ARB_texture_env_add&extensions=GL_ARB_texture_env_combine&extensions=GL_ARB_texture_env_crossbar&extensions=GL_ARB_texture_env_dot3&extensions=GL_ARB_texture_filter_minmax&extensions=GL_ARB_texture_float&extensions=GL_ARB_texture_gather&extensions=GL_ARB_texture_mirror_clamp_to_edge&extensions=GL_ARB_texture_mirrored_repeat&extensions=GL_ARB_texture_multisample&extensions=GL_ARB_texture_non_power_of_two&extensions=GL_ARB_texture_query_levels&extensions=GL_ARB_texture_query_lod&extensions=GL_ARB_texture_rectangle&extensions=GL_ARB_texture_rg&extensions=GL_ARB_texture_rgb10_a2ui&extensions=GL_ARB_texture_stencil8&extensions=GL_ARB_texture_storage&extensions=GL_ARB_texture_storage_multisample&extensions=GL_ARB_texture_swizzle&extensions=GL_ARB_texture_view&extensions=GL_ARB_timer_query&extensions=GL_ARB_transform_feedback2&extensions=GL_ARB_transform_feedback3&extensions=GL_ARB_transform_feedback_instanced&extensions=GL_ARB_transform_feedback_overflow_query&extensions=GL_ARB_transpose_matrix&extensions=GL_ARB_uniform_buffer_object&extensions=GL_ARB_vertex_array_bgra&extensions=GL_ARB_vertex_array_object&extensions=GL_ARB_vertex_attrib_64bit&extensions=GL_ARB_vertex_attrib_binding&extensions=GL_ARB_vertex_blend&extensions=GL_ARB_vertex_buffer_object&extensions=GL_ARB_vertex_program&extensions=GL_ARB_vertex_shader&extensions=GL_ARB_vertex_type_10f_11f_11f_rev&extensions=GL_ARB_vertex_type_2_10_10_10_rev&extensions=GL_ARB_viewport_array&extensions=GL_ARB_window_pos&extensions=GL_ARM_mali_program_binary&extensions=GL_ARM_mali_shader_binary&extensions=GL_ARM_rgba8&extensions=GL_ARM_shader_framebuffer_fetch&extensions=GL_ARM_shader_framebuffer_fetch_depth_stencil&extensions=GL_ATI_draw_buffers&extensions=GL_ATI_element_array&extensions=GL_ATI_envmap_bumpmap&extensions=GL_ATI_fragment_shader&extensions=GL_ATI_map_object_buffer&extensions=GL_ATI_meminfo&extensions=GL_ATI_pixel_format_float&extensions=GL_ATI_pn_triangles&extensions=GL_ATI_separate_stencil&extensions=GL_ATI_text_fragment_shader&extensions=GL_ATI_texture_env_combine3&extensions=GL_ATI_texture_float&extensions=GL_ATI_texture_mirror_once&extensions=GL_ATI_vertex_array_object&extensions=GL_ATI_vertex_attrib_array_object&extensions=GL_ATI_vertex_streams&extensions=GL_DMP_program_binary&extensions=GL_DMP_shader_binary&extensions=GL_EXT_422_pixels&extensions=GL_EXT_YUV_target&extensions=GL_EXT_abgr&extensions=GL_EXT_base_instance&extensions=GL_EXT_bgra&extensions=GL_EXT_bindable_uniform&extensions=GL_EXT_blend_color&extensions=GL_EXT_blend_equation_separate&extensions=GL_EXT_blend_func_extended&extensions=GL_EXT_blend_func_separate&extensions=GL_EXT_blend_logic_op&extensions=GL_EXT_blend_minmax&extensions=GL_EXT_blend_subtract&extensions=GL_EXT_buffer_storage&extensions=GL_EXT_clear_texture&extensions=GL_EXT_clip_cull_distance&extensions=GL_EXT_clip_volume_hint&extensions=GL_EXT_cmyka&extensions=GL_EXT_color_buffer_float&extensions=GL_EXT_color_buffer_half_float&extensions=GL_EXT_color_subtable&extensions=GL_EXT_compiled_vertex_array&extensions=GL_EXT_conservative_depth&extensions=GL_EXT_convolution&extensions=GL_EXT_coordinate_frame&extensions=GL_EXT_copy_image&extensions=GL_EXT_copy_texture&extensions=GL_EXT_cull_vertex&extensions=GL_EXT_debug_label&extensions=GL_EXT_debug_marker&extensions=GL_EXT_depth_bounds_test&extensions=GL_EXT_direct_state_access&extensions=GL_EXT_discard_framebuffer&extensions=GL_EXT_disjoint_timer_query&extensions=GL_EXT_draw_buffers&extensions=GL_EXT_draw_buffers2&extensions=GL_EXT_draw_buffers_indexed&extensions=GL_EXT_draw_elements_base_vertex&extensions=GL_EXT_draw_instanced&extensions=GL_EXT_draw_range_elements&extensions=GL_EXT_draw_transform_feedback&extensions=GL_EXT_float_blend&extensions=GL_EXT_fog_coord&extensions=GL_EXT_framebuffer_blit&extensions=GL_EXT_framebuffer_multisample&extensions=GL_EXT_framebuffer_multisample_blit_scaled&extensions=GL_EXT_framebuffer_object&extensions=GL_EXT_framebuffer_sRGB&extensions=GL_EXT_geometry_point_size&extensions=GL_EXT_geometry_shader&extensions=GL_EXT_geometry_shader4&extensions=GL_EXT_gpu_program_parameters&extensions=GL_EXT_gpu_shader4&extensions=GL_EXT_gpu_shader5&extensions=GL_EXT_histogram&extensions=GL_EXT_index_array_formats&extensions=GL_EXT_index_func&extensions=GL_EXT_index_material&extensions=GL_EXT_index_texture&extensions=GL_EXT_instanced_arrays&extensions=GL_EXT_light_texture&extensions=GL_EXT_map_buffer_range&extensions=GL_EXT_misc_attribute&extensions=GL_EXT_multi_draw_arrays&extensions=GL_EXT_multi_draw_indirect&extensions=GL_EXT_multisample&extensions=GL_EXT_multisampled_compatibility&extensions=GL_EXT_multisampled_render_to_texture&extensions=GL_EXT_multiview_draw_buffers&extensions=GL_EXT_occlusion_query_boolean&extensions=GL_EXT_packed_depth_stencil&extensions=GL_EXT_packed_float&extensions=GL_EXT_packed_pixels&extensions=GL_EXT_paletted_texture&extensions=GL_EXT_pixel_buffer_object&extensions=GL_EXT_pixel_transform&extensions=GL_EXT_pixel_transform_color_table&extensions=GL_EXT_point_parameters&extensions=GL_EXT_polygon_offset&extensions=GL_EXT_polygon_offset_clamp&extensions=GL_EXT_post_depth_coverage&extensions=GL_EXT_primitive_bounding_box&extensions=GL_EXT_protected_textures&extensions=GL_EXT_provoking_vertex&extensions=GL_EXT_pvrtc_sRGB&extensions=GL_EXT_raster_multisample&extensions=GL_EXT_read_format_bgra&extensions=GL_EXT_render_snorm&extensions=GL_EXT_rescale_normal&extensions=GL_EXT_robustness&extensions=GL_EXT_sRGB&extensions=GL_EXT_sRGB_write_control&extensions=GL_EXT_secondary_color&extensions=GL_EXT_separate_shader_objects&extensions=GL_EXT_separate_specular_color&extensions=GL_EXT_shader_framebuffer_fetch&extensions=GL_EXT_shader_group_vote&extensions=GL_EXT_shader_image_load_formatted&extensions=GL_EXT_shader_image_load_store&extensions=GL_EXT_shader_implicit_conversions&extensions=GL_EXT_shader_integer_mix&extensions=GL_EXT_shader_io_blocks&extensions=GL_EXT_shader_non_constant_global_initializers&extensions=GL_EXT_shader_pixel_local_storage&extensions=GL_EXT_shader_pixel_local_storage2&extensions=GL_EXT_shader_texture_lod&extensions=GL_EXT_shadow_funcs&extensions=GL_EXT_shadow_samplers&extensions=GL_EXT_shared_texture_palette&extensions=GL_EXT_sparse_texture&extensions=GL_EXT_sparse_texture2&extensions=GL_EXT_stencil_clear_tag&extensions=GL_EXT_stencil_two_side&extensions=GL_EXT_stencil_wrap&extensions=GL_EXT_subtexture&extensions=GL_EXT_tessellation_point_size&extensions=GL_EXT_tessellation_shader&extensions=GL_EXT_texture&extensions=GL_EXT_texture3D&extensions=GL_EXT_texture_array&extensions=GL_EXT_texture_border_clamp&extensions=GL_EXT_texture_buffer&extensions=GL_EXT_texture_buffer_object&extensions=GL_EXT_texture_compression_dxt1&extensions=GL_EXT_texture_compression_latc&extensions=GL_EXT_texture_compression_rgtc&extensions=GL_EXT_texture_compression_s3tc&extensions=GL_EXT_texture_cube_map&extensions=GL_EXT_texture_cube_map_array&extensions=GL_EXT_texture_env_add&extensions=GL_EXT_texture_env_combine&extensions=GL_EXT_texture_env_dot3&extensions=GL_EXT_texture_filter_anisotropic&extensions=GL_EXT_texture_filter_minmax&extensions=GL_EXT_texture_format_BGRA8888&extensions=GL_EXT_texture_integer&extensions=GL_EXT_texture_lod_bias&extensions=GL_EXT_texture_mirror_clamp&extensions=GL_EXT_texture_norm16&extensions=GL_EXT_texture_object&extensions=GL_EXT_texture_perturb_normal&extensions=GL_EXT_texture_rg&extensions=GL_EXT_texture_sRGB&extensions=GL_EXT_texture_sRGB_R8&extensions=GL_EXT_texture_sRGB_RG8&extensions=GL_EXT_texture_sRGB_decode&extensions=GL_EXT_texture_shared_exponent&extensions=GL_EXT_texture_snorm&extensions=GL_EXT_texture_storage&extensions=GL_EXT_texture_swizzle&extensions=GL_EXT_texture_type_2_10_10_10_REV&extensions=GL_EXT_texture_view&extensions=GL_EXT_timer_query&extensions=GL_EXT_transform_feedback&extensions=GL_EXT_unpack_subimage&extensions=GL_EXT_vertex_array&extensions=GL_EXT_vertex_array_bgra&extensions=GL_EXT_vertex_attrib_64bit&extensions=GL_EXT_vertex_shader&extensions=GL_EXT_vertex_weighting&extensions=GL_EXT_window_rectangles&extensions=GL_EXT_x11_sync_object&extensions=GL_FJ_shader_binary_GCCSO&extensions=GL_GREMEDY_frame_terminator&extensions=GL_GREMEDY_string_marker&extensions=GL_HP_convolution_border_modes&extensions=GL_HP_image_transform&extensions=GL_HP_occlusion_test&extensions=GL_HP_texture_lighting&extensions=GL_IBM_cull_vertex&extensions=GL_IBM_multimode_draw_arrays&extensions=GL_IBM_rasterpos_clip&extensions=GL_IBM_static_data&extensions=GL_IBM_texture_mirrored_repeat&extensions=GL_IBM_vertex_array_lists&extensions=GL_IMG_bindless_texture&extensions=GL_IMG_framebuffer_downsample&extensions=GL_IMG_multisampled_render_to_texture&extensions=GL_IMG_program_binary&extensions=GL_IMG_read_format&extensions=GL_IMG_shader_binary&extensions=GL_IMG_texture_compression_pvrtc&extensions=GL_IMG_texture_compression_pvrtc2&extensions=GL_IMG_texture_filter_cubic&extensions=GL_INGR_blend_func_separate&extensions=GL_INGR_color_clamp&extensions=GL_INGR_interlace_read&extensions=GL_INTEL_conservative_rasterization&extensions=GL_INTEL_fragment_shader_ordering&extensions=GL_INTEL_framebuffer_CMAA&extensions=GL_INTEL_map_texture&extensions=GL_INTEL_parallel_arrays&extensions=GL_INTEL_performance_query&extensions=GL_KHR_blend_equation_advanced&extensions=GL_KHR_blend_equation_advanced_coherent&extensions=GL_KHR_context_flush_control&extensions=GL_KHR_debug&extensions=GL_KHR_no_error&extensions=GL_KHR_robust_buffer_access_behavior&extensions=GL_KHR_robustness&extensions=GL_KHR_texture_compression_astc_hdr&extensions=GL_KHR_texture_compression_astc_ldr&extensions=GL_KHR_texture_compression_astc_sliced_3d&extensions=GL_MESAX_texture_stack&extensions=GL_MESA_pack_invert&extensions=GL_MESA_resize_buffers&extensions=GL_MESA_window_pos&extensions=GL_MESA_ycbcr_texture&extensions=GL_NVX_conditional_render&extensions=GL_NVX_gpu_memory_info&extensions=GL_NV_bindless_multi_draw_indirect&extensions=GL_NV_bindless_multi_draw_indirect_count&extensions=GL_NV_bindless_texture&extensions=GL_NV_blend_equation_advanced&extensions=GL_NV_blend_equation_advanced_coherent&extensions=GL_NV_blend_square&extensions=GL_NV_clip_space_w_scaling&extensions=GL_NV_command_list&extensions=GL_NV_compute_program5&extensions=GL_NV_conditional_render&extensions=GL_NV_conservative_raster&extensions=GL_NV_conservative_raster_dilate&extensions=GL_NV_conservative_raster_pre_snap_triangles&extensions=GL_NV_copy_buffer&extensions=GL_NV_copy_depth_to_color&extensions=GL_NV_copy_image&extensions=GL_NV_coverage_sample&extensions=GL_NV_deep_texture3D&extensions=GL_NV_depth_buffer_float&extensions=GL_NV_depth_clamp&extensions=GL_NV_depth_nonlinear&extensions=GL_NV_draw_buffers&extensions=GL_NV_draw_instanced&extensions=GL_NV_draw_texture&extensions=GL_NV_evaluators&extensions=GL_NV_explicit_attrib_location&extensions=GL_NV_explicit_multisample&extensions=GL_NV_fbo_color_attachments&extensions=GL_NV_fence&extensions=GL_NV_fill_rectangle&extensions=GL_NV_float_buffer&extensions=GL_NV_fog_distance&extensions=GL_NV_fragment_coverage_to_color&extensions=GL_NV_fragment_program&extensions=GL_NV_fragment_program2&extensions=GL_NV_fragment_program4&extensions=GL_NV_fragment_program_option&extensions=GL_NV_fragment_shader_interlock&extensions=GL_NV_framebuffer_blit&extensions=GL_NV_framebuffer_mixed_samples&extensions=GL_NV_framebuffer_multisample&extensions=GL_NV_framebuffer_multisample_coverage&extensions=GL_NV_generate_mipmap_sRGB&extensions=GL_NV_geometry_program4&extensions=GL_NV_geometry_shader4&extensions=GL_NV_geometry_shader_passthrough&extensions=GL_NV_gpu_program4&extensions=GL_NV_gpu_program5&extensions=GL_NV_gpu_program5_mem_extended&extensions=GL_NV_gpu_shader5&extensions=GL_NV_half_float&extensions=GL_NV_image_formats&extensions=GL_NV_instanced_arrays&extensions=GL_NV_internalformat_sample_query&extensions=GL_NV_light_max_exponent&extensions=GL_NV_multisample_coverage&extensions=GL_NV_multisample_filter_hint&extensions=GL_NV_non_square_matrices&extensions=GL_NV_occlusion_query&extensions=GL_NV_packed_depth_stencil&extensions=GL_NV_parameter_buffer_object&extensions=GL_NV_parameter_buffer_object2&extensions=GL_NV_path_rendering&extensions=GL_NV_path_rendering_shared_edge&extensions=GL_NV_pixel_data_range&extensions=GL_NV_point_sprite&extensions=GL_NV_polygon_mode&extensions=GL_NV_present_video&extensions=GL_NV_primitive_restart&extensions=GL_NV_read_buffer&extensions=GL_NV_read_buffer_front&extensions=GL_NV_read_depth&extensions=GL_NV_read_depth_stencil&extensions=GL_NV_read_stencil&extensions=GL_NV_register_combiners&extensions=GL_NV_register_combiners2&extensions=GL_NV_robustness_video_memory_purge&extensions=GL_NV_sRGB_formats&extensions=GL_NV_sample_locations&extensions=GL_NV_sample_mask_override_coverage&extensions=GL_NV_shader_atomic_counters&extensions=GL_NV_shader_atomic_float&extensions=GL_NV_shader_atomic_float64&extensions=GL_NV_shader_atomic_fp16_vector&extensions=GL_NV_shader_atomic_int64&extensions=GL_NV_shader_buffer_load&extensions=GL_NV_shader_buffer_store&extensions=GL_NV_shader_noperspective_interpolation&extensions=GL_NV_shader_storage_buffer_object&extensions=GL_NV_shader_thread_group&extensions=GL_NV_shader_thread_shuffle&extensions=GL_NV_shadow_samplers_array&extensions=GL_NV_shadow_samplers_cube&extensions=GL_NV_stereo_view_rendering&extensions=GL_NV_tessellation_program5&extensions=GL_NV_texgen_emboss&extensions=GL_NV_texgen_reflection&extensions=GL_NV_texture_barrier&extensions=GL_NV_texture_border_clamp&extensions=GL_NV_texture_compression_s3tc_update&extensions=GL_NV_texture_compression_vtc&extensions=GL_NV_texture_env_combine4&extensions=GL_NV_texture_expand_normal&extensions=GL_NV_texture_multisample&extensions=GL_NV_texture_npot_2D_mipmap&extensions=GL_NV_texture_rectangle&extensions=GL_NV_texture_shader&extensions=GL_NV_texture_shader2&extensions=GL_NV_texture_shader3&extensions=GL_NV_transform_feedback&extensions=GL_NV_transform_feedback2&extensions=GL_NV_uniform_buffer_unified_memory&extensions=GL_NV_vdpau_interop&extensions=GL_NV_vertex_array_range&extensions=GL_NV_vertex_array_range2&extensions=GL_NV_vertex_attrib_integer_64bit&extensions=GL_NV_vertex_buffer_unified_memory&extensions=GL_NV_vertex_program&extensions=GL_NV_vertex_program1_1&extensions=GL_NV_vertex_program2&extensions=GL_NV_vertex_program2_option&extensions=GL_NV_vertex_program3&extensions=GL_NV_vertex_program4&extensions=GL_NV_video_capture&extensions=GL_NV_viewport_array&extensions=GL_NV_viewport_array2&extensions=GL_NV_viewport_swizzle&extensions=GL_OES_EGL_image&extensions=GL_OES_EGL_image_external&extensions=GL_OES_EGL_image_external_essl3&extensions=GL_OES_byte_coordinates&extensions=GL_OES_compressed_ETC1_RGB8_sub_texture&extensions=GL_OES_compressed_ETC1_RGB8_texture&extensions=GL_OES_compressed_paletted_texture&extensions=GL_OES_copy_image&extensions=GL_OES_depth24&extensions=GL_OES_depth32&extensions=GL_OES_depth_texture&extensions=GL_OES_draw_buffers_indexed&extensions=GL_OES_draw_elements_base_vertex&extensions=GL_OES_element_index_uint&extensions=GL_OES_fbo_render_mipmap&extensions=GL_OES_fixed_point&extensions=GL_OES_fragment_precision_high&extensions=GL_OES_geometry_point_size&extensions=GL_OES_geometry_shader&extensions=GL_OES_get_program_binary&extensions=GL_OES_gpu_shader5&extensions=GL_OES_mapbuffer&extensions=GL_OES_packed_depth_stencil&extensions=GL_OES_primitive_bounding_box&extensions=GL_OES_query_matrix&extensions=GL_OES_read_format&extensions=GL_OES_required_internalformat&extensions=GL_OES_rgb8_rgba8&extensions=GL_OES_sample_shading&extensions=GL_OES_sample_variables&extensions=GL_OES_shader_image_atomic&extensions=GL_OES_shader_io_blocks&extensions=GL_OES_shader_multisample_interpolation&extensions=GL_OES_single_precision&extensions=GL_OES_standard_derivatives&extensions=GL_OES_stencil1&extensions=GL_OES_stencil4&extensions=GL_OES_surfaceless_context&extensions=GL_OES_tessellation_point_size&extensions=GL_OES_tessellation_shader&extensions=GL_OES_texture_3D&extensions=GL_OES_texture_border_clamp&extensions=GL_OES_texture_buffer&extensions=GL_OES_texture_compression_astc&extensions=GL_OES_texture_cube_map_array&extensions=GL_OES_texture_float&extensions=GL_OES_texture_float_linear&extensions=GL_OES_texture_half_float&extensions=GL_OES_texture_half_float_linear&extensions=GL_OES_texture_npot&extensions=GL_OES_texture_stencil8&extensions=GL_OES_texture_storage_multisample_2d_array&extensions=GL_OES_texture_view&extensions=GL_OES_vertex_array_object&extensions=GL_OES_vertex_half_float&extensions=GL_OES_vertex_type_10_10_10_2&extensions=GL_OES_viewport_array&extensions=GL_OML_interlace&extensions=GL_OML_resample&extensions=GL_OML_subsample&extensions=GL_OVR_multiview&extensions=GL_OVR_multiview2&extensions=GL_OVR_multiview_multisampled_render_to_texture&extensions=GL_PGI_misc_hints&extensions=GL_PGI_vertex_hints&extensions=GL_QCOM_alpha_test&extensions=GL_QCOM_binning_control&extensions=GL_QCOM_driver_control&extensions=GL_QCOM_extended_get&extensions=GL_QCOM_extended_get2&extensions=GL_QCOM_perfmon_global_mode&extensions=GL_QCOM_tiled_rendering&extensions=GL_QCOM_writeonly_rendering&extensions=GL_REND_screen_coordinates&extensions=GL_S3_s3tc&extensions=GL_SGIS_detail_texture&extensions=GL_SGIS_fog_function&extensions=GL_SGIS_generate_mipmap&extensions=GL_SGIS_multisample&extensions=GL_SGIS_pixel_texture&extensions=GL_SGIS_point_line_texgen&extensions=GL_SGIS_point_parameters&extensions=GL_SGIS_sharpen_texture&extensions=GL_SGIS_texture4D&extensions=GL_SGIS_texture_border_clamp&extensions=GL_SGIS_texture_color_mask&extensions=GL_SGIS_texture_edge_clamp&extensions=GL_SGIS_texture_filter4&extensions=GL_SGIS_texture_lod&extensions=GL_SGIS_texture_select&extensions=GL_SGIX_async&extensions=GL_SGIX_async_histogram&extensions=GL_SGIX_async_pixel&extensions=GL_SGIX_blend_alpha_minmax&extensions=GL_SGIX_calligraphic_fragment&extensions=GL_SGIX_clipmap&extensions=GL_SGIX_convolution_accuracy&extensions=GL_SGIX_depth_pass_instrument&extensions=GL_SGIX_depth_texture&extensions=GL_SGIX_flush_raster&extensions=GL_SGIX_fog_offset&extensions=GL_SGIX_fragment_lighting&extensions=GL_SGIX_framezoom&extensions=GL_SGIX_igloo_interface&extensions=GL_SGIX_instruments&extensions=GL_SGIX_interlace&extensions=GL_SGIX_ir_instrument1&extensions=GL_SGIX_list_priority&extensions=GL_SGIX_pixel_texture&extensions=GL_SGIX_pixel_tiles&extensions=GL_SGIX_polynomial_ffd&extensions=GL_SGIX_reference_plane&extensions=GL_SGIX_resample&extensions=GL_SGIX_scalebias_hint&extensions=GL_SGIX_shadow&extensions=GL_SGIX_shadow_ambient&extensions=GL_SGIX_sprite&extensions=GL_SGIX_subsample&extensions=GL_SGIX_tag_sample_buffer&extensions=GL_SGIX_texture_add_env&extensions=GL_SGIX_texture_coordinate_clamp&extensions=GL_SGIX_texture_lod_bias&extensions=GL_SGIX_texture_multi_buffer&extensions=GL_SGIX_texture_scale_bias&extensions=GL_SGIX_vertex_preclip&extensions=GL_SGIX_ycrcb&extensions=GL_SGIX_ycrcb_subsample&extensions=GL_SGIX_ycrcba&extensions=GL_SGI_color_matrix&extensions=GL_SGI_color_table&extensions=GL_SGI_texture_color_table&extensions=GL_SUNX_constant_data&extensions=GL_SUN_convolution_border_modes&extensions=GL_SUN_global_alpha&extensions=GL_SUN_mesh_array&extensions=GL_SUN_slice_accum&extensions=GL_SUN_triangle_list&extensions=GL_SUN_vertex&extensions=GL_VIV_shader_binary&extensions=GL_WIN_phong_shading&extensions=GL_WIN_specular_fog&language=c&specification=gl&loader=on) or you can create your own loader by visiting the [Glad site](http://glad.dav1d.de/).\n\nOnce SFML and Glad have been installed on your system you have to edit the Makefile provided so that you can build the demo. There are two variables that need to be edited: SFML_DIR and GLAD_DIR. Make these point to your SFML root folder and Glad root folder respectively.\n\nOn Linux there is an extra step. You need to install the udev development files.\n"
  },
  {
    "path": "demo/sfml_opengl3/main.cpp",
    "content": "/* nuklear - v1.32.0 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <limits.h>\n#include <time.h>\n\n#include <SFML/Window.hpp>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_SFML_GL3_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_sfml_gl3.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define MAX_VERTEX_BUFFER 512 * 1024\n#define MAX_ELEMENT_BUFFER 128 * 1024\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nint main(void)\n{\n    /* Platform */\n    sf::ContextSettings settings(24, 8, 4, 3, 3);\n    sf::Window win(sf::VideoMode(WINDOW_WIDTH, WINDOW_HEIGHT), \"Demo\", sf::Style::Default, settings);\n    win.setVerticalSyncEnabled(true);\n    win.setActive(true);\n    if(!gladLoadGL()) { /* Load OpenGL extensions */\n        printf(\"Failed to load OpenGL extensions!\\n\");\n        return -1;\n    }\n    glViewport(0, 0, win.getSize().x, win.getSize().y);\n\n    /* GUI */\n    struct nk_context *ctx;\n    ctx = nk_sfml_init(&win);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    struct nk_font_atlas *atlas;\n    nk_sfml_font_stash_begin(&atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Roboto-Regular.ttf\", 14, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_sfml_font_stash_end();\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &droid->handle);*/\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    struct nk_colorf bg;\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (win.isOpen())\n    {\n        /* Input */\n        sf::Event evt;\n        nk_input_begin(ctx);\n        while(win.pollEvent(evt)) {\n            if(evt.type == sf::Event::Closed)\n                win.close();\n            else if(evt.type == sf::Event::Resized)\n                glViewport(0, 0, evt.size.width, evt.size.height);\n\n            nk_sfml_handle_event(&evt);\n        }\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 230, 250),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        win.setActive(true);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(bg.r, bg.g, bg.b, bg.a);\n        /* IMPORTANT: `nk_sfml_render` modifies some global OpenGL state\n        * with blending, scissor, face culling and depth test and defaults everything\n        * back into a default state. Make sure to either save and restore or\n        * reset your own state after drawing rendering the UI. */\n        nk_sfml_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);\n        win.display();\n    }\n    nk_sfml_shutdown();\n    return 0;\n}\n\n"
  },
  {
    "path": "demo/sfml_opengl3/nuklear_sfml_gl3.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_SFML_GL3_H_\n#define NK_SFML_GL3_H_\n\n/* Feel free to edit here and include your own extension wrangler */\n#include <glad/glad.h>\n/* I use GLAD but you can use GLEW or what you like */\n\n#include <SFML/Window.hpp>\n\nNK_API struct nk_context*   nk_sfml_init(sf::Window* window);\nNK_API void                 nk_sfml_font_stash_begin(struct nk_font_atlas** atlas);\nNK_API void                 nk_sfml_font_stash_end(void);\nNK_API int                  nk_sfml_handle_event(sf::Event* event);\nNK_API void                 nk_sfml_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);\nNK_API void                 nk_sfml_shutdown(void);\n\nNK_API void                 nk_sfml_device_create(void);\nNK_API void                 nk_sfml_device_destroy(void);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n #ifdef NK_SFML_GL3_IMPLEMENTATION\n#include <cstring>\n#include <assert.h>\n#include <string>\n\nstruct nk_sfml_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint vbo, vao, ebo;\n    GLuint prog;\n    GLuint vert_shdr;\n    GLuint frag_shdr;\n    GLint attrib_pos;\n    GLint attrib_uv;\n    GLint attrib_col;\n    GLint uniform_tex;\n    GLint uniform_proj;\n    GLuint font_tex;\n};\nstruct nk_sfml_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\nstatic struct nk_sfml {\n    sf::Window* window;\n    struct nk_sfml_device ogl;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    sf::Clock* frame_delta_clock;\n} sfml;\n\n#ifdef __APPLE__\n  #define NK_SHADER_VERSION \"#version 150\\n\"\n#else\n  #define NK_SHADER_VERSION \"#version 300 es\\n\"\n#endif\n\nNK_API void\nnk_sfml_device_create(void)\n{\n    GLint status;\n    static const GLchar* vertex_shader =\n        NK_SHADER_VERSION\n        \"uniform mat4 ProjMtx;\\n\"\n        \"in vec2 Position;\\n\"\n        \"in vec2 TexCoord;\\n\"\n        \"in vec4 Color;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main() {\\n\"\n        \"   Frag_UV = TexCoord;\\n\"\n        \"   Frag_Color = Color;\\n\"\n        \"   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\\n\"\n        \"}\\n\";\n    static const GLchar *fragment_shader =\n        NK_SHADER_VERSION\n        \"precision mediump float;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"out vec4 Out_Color;\\n\"\n        \"void main(){\\n\"\n        \"   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    struct nk_sfml_device* dev = &sfml.ogl;\n    nk_buffer_init_default(&dev->cmds);\n\n    dev->prog = glCreateProgram();\n    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);\n    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);\n\n    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);\n    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);\n    glCompileShader(dev->vert_shdr);\n    glCompileShader(dev->frag_shdr);\n\n    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n\n    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n\n    glAttachShader(dev->prog, dev->vert_shdr);\n    glAttachShader(dev->prog, dev->frag_shdr);\n    glLinkProgram(dev->prog);\n\n    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);\n    assert(status == GL_TRUE);\n\n    dev->uniform_tex = glGetUniformLocation(dev->prog, \"Texture\");\n    dev->uniform_proj = glGetUniformLocation(dev->prog, \"ProjMtx\");\n    dev->attrib_pos = glGetAttribLocation(dev->prog, \"Position\");\n    dev->attrib_uv = glGetAttribLocation(dev->prog, \"TexCoord\");\n    dev->attrib_col = glGetAttribLocation(dev->prog, \"Color\");\n    {\n        /* buffer setup */\n        GLsizei vs = sizeof(struct nk_sfml_vertex);\n        size_t vp = NK_OFFSETOF(struct nk_sfml_vertex, position);\n        size_t vt = NK_OFFSETOF(struct nk_sfml_vertex, uv);\n        size_t vc = NK_OFFSETOF(struct nk_sfml_vertex, col);\n\n        glGenBuffers(1, &dev->vbo);\n        glGenBuffers(1, &dev->ebo);\n        glGenVertexArrays(1, &dev->vao);\n\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glEnableVertexAttribArray((GLuint)dev->attrib_pos);\n        glEnableVertexAttribArray((GLuint)dev->attrib_uv);\n        glEnableVertexAttribArray((GLuint)dev->attrib_col);\n\n        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);\n        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);\n        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);\n    }\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n}\n\nNK_API void\nnk_sfml_device_destroy(void)\n{\n    struct nk_sfml_device* dev = &sfml.ogl;\n\n    glDetachShader(dev->prog, dev->vert_shdr);\n    glDetachShader(dev->prog, dev->frag_shdr);\n    glDeleteShader(dev->vert_shdr);\n    glDeleteShader(dev->vert_shdr);\n    glDeleteProgram(dev->prog);\n    glDeleteTextures(1, &dev->font_tex);\n    glDeleteBuffers(1, &dev->vbo);\n    glDeleteBuffers(1, &dev->ebo);\n    nk_buffer_free(&dev->cmds);\n}\n\nNK_INTERN void\nnk_sfml_device_upload_atlas(const void* image, int width, int height)\n{\n    struct nk_sfml_device* dev = &sfml.ogl;\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nNK_API void\nnk_sfml_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)\n{\n    /* setup global state */\n    struct nk_sfml_device* dev = &sfml.ogl;\n    int window_width = sfml.window->getSize().x;\n    int window_height = sfml.window->getSize().y;\n    GLfloat ortho[4][4] = {\n        {  2.0f,  0.0f,  0.0f, 0.0f },\n        {  0.0f, -2.0f,  0.0f, 0.0f },\n        {  0.0f,  0.0f, -1.0f, 0.0f },\n        { -1.0f,  1.0f,  0.0f, 1.0f },\n    };\n\n    sfml.ctx.delta_time_seconds = (float)((double)sfml.frame_delta_clock->getElapsedTime().asMicroseconds() / 1000000);\n    sfml.frame_delta_clock->restart();\n\n    ortho[0][0] /= (GLfloat)window_width;\n    ortho[1][1] /= (GLfloat)window_height;\n\n    glViewport(0, 0, window_width, window_height);\n    glEnable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glActiveTexture(GL_TEXTURE0);\n\n    /* setup program */\n    glUseProgram(dev->prog);\n    glUniform1i(dev->uniform_tex, 0);\n    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        void *vertices, *elements;\n        const nk_draw_index *offset = NULL;\n\n        /* allocate vertex and element buffer */\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);\n\n        /* load vertices/elements directly into vertex/element buffer */\n        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);\n        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] =  {\n                {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, position)},\n                {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_sfml_vertex, uv)},\n                {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_sfml_vertex, col)},\n                {NK_VERTEX_LAYOUT_END}\n            };\n\n            memset(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_sfml_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_sfml_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            struct nk_buffer vbuf, ebuf;\n            nk_buffer_init_fixed(&vbuf, vertices, (nk_size)max_vertex_buffer);\n            nk_buffer_init_fixed(&ebuf, elements, (nk_size)max_element_buffer);\n            nk_convert(&sfml.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n        }\n        glUnmapBuffer(GL_ARRAY_BUFFER);\n        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);\n\n        /* iterate over and execute each draw command */\n        nk_draw_foreach(cmd, &sfml.ctx, &dev->cmds)\n        {\n            if (!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor(\n                (GLint)(cmd->clip_rect.x),\n                (GLint)((window_height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),\n                (GLint)(cmd->clip_rect.w),\n                (GLint)(cmd->clip_rect.h));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(&sfml.ctx);\n        nk_buffer_clear(&dev->cmds);\n    }\n    glUseProgram(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n    glDisable(GL_BLEND);\n    glDisable(GL_SCISSOR_TEST);\n}\n\nstatic void\nnk_sfml_clipboard_paste(nk_handle usr, struct nk_text_edit* edit)\n{\n#if 0\n    /* Not Implemented in SFML */\n    (void)usr;\n    sf::Clipboard clipboard(sfml.window);\n    const char* text = clipboard.getText();\n    if(text) nk_textedit_paste(edit, text, nk_strlen(text));\n#else\n    NK_UNUSED(usr);\n    NK_UNUSED(edit);\n#endif\n}\nstatic void\nnk_sfml_clipboard_copy(nk_handle usr, const char* text, int len)\n{\n#if 0\n    char* str = 0;\n    (void)usr;\n    if(!len) return;\n    str = (char*)malloc((size_t)len+1);\n    if(!str) return;\n    memcpy(str, text, (size_t)len);\n    str[len] = '\\0';\n\n    /* Not Implemented in SFML */\n    sf::Clipboard clipboard(sfml.window);\n    clipboard.setText(str);\n    free(str);\n#else\n    NK_UNUSED(usr);\n    NK_UNUSED(text);\n    NK_UNUSED(len);\n#endif\n}\n\nNK_API struct nk_context*\nnk_sfml_init(sf::Window* window)\n{\n    sfml.window = window;\n    nk_init_default(&sfml.ctx, 0);\n    sfml.ctx.clip.copy = nk_sfml_clipboard_copy;\n    sfml.ctx.clip.paste = nk_sfml_clipboard_paste;\n    sfml.ctx.clip.userdata = nk_handle_ptr(0);\n    nk_sfml_device_create();\n    sfml.frame_delta_clock = new sf::Clock();\n    return &sfml.ctx;\n}\n\nNK_API void\nnk_sfml_font_stash_begin(struct nk_font_atlas** atlas)\n{\n    nk_font_atlas_init_default(&sfml.atlas);\n    nk_font_atlas_begin(&sfml.atlas);\n    *atlas = &sfml.atlas;\n}\n\nNK_API void\nnk_sfml_font_stash_end()\n{\n    const void* image;\n    int w, h;\n    image = nk_font_atlas_bake(&sfml.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_sfml_device_upload_atlas(image, w, h);\n    nk_font_atlas_end(&sfml.atlas, nk_handle_id((int)sfml.ogl.font_tex), &sfml.ogl.tex_null);\n    if(sfml.atlas.default_font)\n        nk_style_set_font(&sfml.ctx, &sfml.atlas.default_font->handle);\n}\n\nNK_API int\nnk_sfml_handle_event(sf::Event* evt)\n{\n    struct nk_context* ctx = &sfml.ctx;\n    /* optional grabbing behavior */\n    if(ctx->input.mouse.grab)\n        ctx->input.mouse.grab = 0;\n    else if(ctx->input.mouse.ungrab) {\n        int x = (int)ctx->input.mouse.prev.x;\n        int y = (int)ctx->input.mouse.prev.y;\n        sf::Mouse::setPosition(sf::Vector2i(x, y), *sfml.window);\n        ctx->input.mouse.ungrab = 0;\n    }\n    if(evt->type == sf::Event::KeyReleased || evt->type == sf::Event::KeyPressed)\n    {\n        int down = evt->type == sf::Event::KeyPressed;\n        sf::Keyboard::Key key = evt->key.code;\n        if(key == sf::Keyboard::RShift || key == sf::Keyboard::LShift)\n            nk_input_key(ctx, NK_KEY_SHIFT, down);\n        else if(key == sf::Keyboard::Delete)\n            nk_input_key(ctx, NK_KEY_DEL, down);\n        else if(key == sf::Keyboard::Enter)\n            nk_input_key(ctx, NK_KEY_ENTER, down);\n        else if(key == sf::Keyboard::Tab)\n            nk_input_key(ctx, NK_KEY_TAB, down);\n        else if(key == sf::Keyboard::BackSpace)\n            nk_input_key(ctx, NK_KEY_BACKSPACE, down);\n        else if(key == sf::Keyboard::Home) {\n            nk_input_key(ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_START, down);\n        } else if(key == sf::Keyboard::End) {\n            nk_input_key(ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_END, down);\n        } else if(key == sf::Keyboard::PageDown)\n            nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);\n        else if(key == sf::Keyboard::PageUp)\n            nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);\n        else if(key == sf::Keyboard::Z)\n            nk_input_key(ctx, NK_KEY_TEXT_UNDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::R)\n            nk_input_key(ctx, NK_KEY_TEXT_REDO, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::C)\n            nk_input_key(ctx, NK_KEY_COPY, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::V)\n            nk_input_key(ctx, NK_KEY_PASTE, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::X)\n            nk_input_key(ctx, NK_KEY_CUT, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::B)\n            nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::E)\n            nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down && sf::Keyboard::isKeyPressed(sf::Keyboard::LControl));\n        else if(key == sf::Keyboard::Up)\n            nk_input_key(ctx, NK_KEY_UP, down);\n        else if(key == sf::Keyboard::Down)\n            nk_input_key(ctx, NK_KEY_DOWN, down);\n        else if(key == sf::Keyboard::Left) {\n            if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else nk_input_key(ctx, NK_KEY_LEFT, down);\n        } else if(key == sf::Keyboard::Right) {\n            if(sf::Keyboard::isKeyPressed(sf::Keyboard::LControl))\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else nk_input_key(ctx, NK_KEY_RIGHT, down);\n        } else return 0;\n        return 1;\n    } else if(evt->type == sf::Event::MouseButtonPressed || evt->type == sf::Event::MouseButtonReleased) {\n        int down = evt->type == sf::Event::MouseButtonPressed;\n        const int x = evt->mouseButton.x, y = evt->mouseButton.y;\n        if(evt->mouseButton.button == sf::Mouse::Left)\n            nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);\n        if(evt->mouseButton.button == sf::Mouse::Middle)\n            nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);\n        if(evt->mouseButton.button == sf::Mouse::Right)\n            nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);\n        if(evt->mouseButton.button == sf::Mouse::XButton1)\n            nk_input_button(ctx, NK_BUTTON_X1, x, y, down);\n        if(evt->mouseButton.button == sf::Mouse::XButton2)\n            nk_input_button(ctx, NK_BUTTON_X2, x, y, down);\n        else return 0;\n        return 1;\n    } else if(evt->type == sf::Event::MouseMoved) {\n        nk_input_motion(ctx, evt->mouseMove.x, evt->mouseMove.y);\n        return 1;\n    } else if(evt->type == sf::Event::TouchBegan || evt->type == sf::Event::TouchEnded) {\n        int down = evt->type == sf::Event::TouchBegan;\n        const int x = evt->touch.x, y = evt->touch.y;\n        nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);\n        return 1;\n    } else if(evt->type == sf::Event::TouchMoved) {\n        if(ctx->input.mouse.grabbed) {\n            int x = (int)ctx->input.mouse.prev.x;\n            int y = (int)ctx->input.mouse.prev.y;\n            nk_input_motion(ctx, x + evt->touch.x, y + evt->touch.y);\n        } else nk_input_motion(ctx, evt->touch.x, evt->touch.y);\n        return 1;\n    } else if(evt->type == sf::Event::TextEntered) {\n        /* 8 ~ backspace */\n        if (evt->text.unicode != 8) {\n            nk_input_unicode(ctx, evt->text.unicode);\n        }\n        return 1;\n    } else if(evt->type == sf::Event::MouseWheelScrolled) {\n        nk_input_scroll(ctx, nk_vec2(0,evt->mouseWheelScroll.delta));\n        return 1;\n    }\n    return 0;\n}\n\nNK_API\nvoid nk_sfml_shutdown()\n{\n    nk_font_atlas_clear(&sfml.atlas);\n    nk_free(&sfml.ctx);\n    nk_sfml_device_destroy();\n    delete sfml.frame_delta_clock;\n    memset(&sfml, 0, sizeof(sfml));\n}\n\n#endif\n"
  },
  {
    "path": "demo/x11/Makefile",
    "content": "# Install\nBIN = demo\n\n# Flags\nCFLAGS += -g -std=c89 -Wall -Wextra -pedantic -Wno-unused-function -D_POSIX_C_SOURCE=200809L\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\nX11_CFLAGS += ${shell pkg-config --cflags x11}\nX11_LDFLAGS += ${shell pkg-config --libs x11} -lm\n\nXFT_CFLAGS += ${shell pkg-config --cflags xft x11} -DNK_XLIB_USE_XFT\nXFT_LDFLAGS += ${shell pkg-config --libs xft x11} -lm\n\nall: $(BIN) $(BIN)-xft\n\n$(BIN):\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) $(X11_CFLAGS) -o bin/$(BIN) ${LDFLAGS} ${X11_LDFLAGS}\n\n$(BIN)-xft:\n\t@mkdir -p bin\n\trm -f bin/$(BIN)-xft $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) $(XFT_CFLAGS) -o bin/$(BIN)-xft ${LDFLAGS} ${LDFLAGS} ${XFT_LDFLAGS}\n"
  },
  {
    "path": "demo/x11/main.c",
    "content": "/* nuklear - v1.32.0 - public domain */\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#include <string.h>\n#include <limits.h>\n#include <math.h>\n#include <sys/time.h>\n#include <unistd.h>\n#include <time.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_IMPLEMENTATION\n#define NK_XLIB_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_xlib.h\"\n\n#define DTIME           20\n#define WINDOW_WIDTH    800\n#define WINDOW_HEIGHT   600\n\ntypedef struct XWindow XWindow;\nstruct XWindow {\n    Display *dpy;\n    Window root;\n    Visual *vis;\n    Colormap cmap;\n    XWindowAttributes attr;\n    XSetWindowAttributes swa;\n    Window win;\n    int screen;\n    XFont *font;\n    unsigned int width;\n    unsigned int height;\n    Atom wm_delete_window;\n};\n\nstatic void\ndie(const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    fputs(\"\\n\", stderr);\n    exit(EXIT_FAILURE);\n}\n\nstatic long\ntimestamp(void)\n{\n    struct timeval tv;\n    if (gettimeofday(&tv, NULL) < 0) return 0;\n    return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000);\n}\n\nstatic void\nsleep_for(long t)\n{\n    struct timespec req;\n    const time_t sec = (int)(t/1000);\n    const long ms = t - (sec * 1000);\n    req.tv_sec = sec;\n    req.tv_nsec = ms * 1000000L;\n    while(-1 == nanosleep(&req, &req));\n}\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nint\nmain(void)\n{\n    long dt;\n    long started;\n    int running = 1;\n    XWindow xw;\n    struct nk_context *ctx;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    /* X11 */\n    memset(&xw, 0, sizeof xw);\n    xw.dpy = XOpenDisplay(NULL);\n    if (!xw.dpy) die(\"Could not open a display; perhaps $DISPLAY is not set?\");\n    xw.root = DefaultRootWindow(xw.dpy);\n    xw.screen = XDefaultScreen(xw.dpy);\n    xw.vis = XDefaultVisual(xw.dpy, xw.screen);\n    xw.cmap = XCreateColormap(xw.dpy,xw.root,xw.vis,AllocNone);\n\n    xw.swa.colormap = xw.cmap;\n    xw.swa.event_mask =\n        ExposureMask | KeyPressMask | KeyReleaseMask |\n        ButtonPress | ButtonReleaseMask| ButtonMotionMask |\n        Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|\n        PointerMotionMask | KeymapStateMask;\n    xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0,\n        XDefaultDepth(xw.dpy, xw.screen), InputOutput,\n        xw.vis, CWEventMask | CWColormap, &xw.swa);\n\n    XStoreName(xw.dpy, xw.win, \"X11\");\n    XMapWindow(xw.dpy, xw.win);\n    xw.wm_delete_window = XInternAtom(xw.dpy, \"WM_DELETE_WINDOW\", False);\n    XSetWMProtocols(xw.dpy, xw.win, &xw.wm_delete_window, 1);\n    XGetWindowAttributes(xw.dpy, xw.win, &xw.attr);\n    xw.width = (unsigned int)xw.attr.width;\n    xw.height = (unsigned int)xw.attr.height;\n\n    /* GUI */\n#ifdef NK_XLIB_USE_XFT\n    xw.font = nk_xfont_create(xw.dpy, \"Arial\");\n    ctx = nk_xlib_init(xw.font, xw.dpy, xw.screen, xw.win,\n                       xw.vis, xw.cmap, xw.width, xw.height);\n#else\n    xw.font = nk_xfont_create(xw.dpy, \"fixed\");\n    ctx = nk_xlib_init(xw.font, xw.dpy, xw.screen, xw.win, xw.width, xw.height);\n#endif\n\n    while (running)\n    {\n        /* Input */\n        XEvent evt;\n        started = timestamp();\n        nk_input_begin(ctx);\n        while (XPending(xw.dpy)) {\n            XNextEvent(xw.dpy, &evt);\n            if (evt.type == ClientMessage) goto cleanup;\n            if (XFilterEvent(&evt, xw.win)) continue;\n            nk_xlib_handle_event(xw.dpy, xw.screen, xw.win, &evt);\n        }\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 200, 200),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n        }\n        nk_end(ctx);\n        if (nk_window_is_hidden(ctx, \"Demo\")) break;\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        XClearWindow(xw.dpy, xw.win);\n        nk_xlib_render(xw.win, nk_rgb(30,30,30));\n        XFlush(xw.dpy);\n\n        /* Timing */\n        dt = timestamp() - started;\n        if (dt < DTIME)\n            sleep_for(DTIME - dt);\n    }\n\ncleanup:\n    nk_xfont_del(xw.dpy, xw.font);\n    nk_xlib_shutdown();\n    XUnmapWindow(xw.dpy, xw.win);\n    XFreeColormap(xw.dpy, xw.cmap);\n    XDestroyWindow(xw.dpy, xw.win);\n    XCloseDisplay(xw.dpy);\n    return 0;\n}\n\n"
  },
  {
    "path": "demo/x11/nuklear_xlib.h",
    "content": "/*\n * Nuklear - v1.40.8 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2017 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_XLIB_H_\n#define NK_XLIB_H_\n\n#include <X11/Xlib.h>\n\ntypedef struct XFont XFont;\n#ifdef NK_XLIB_USE_XFT\nNK_API struct nk_context*   nk_xlib_init(XFont*, Display*, int scrn, Window root, Visual *vis, Colormap cmap, unsigned w, unsigned h);\n#else\nNK_API struct nk_context*   nk_xlib_init(XFont*, Display*, int scrn, Window root, unsigned w, unsigned h);\n#endif\nNK_API int                  nk_xlib_handle_event(Display*, int scrn, Window, XEvent*);\nNK_API void                 nk_xlib_render(Drawable screen, struct nk_color clear);\nNK_API void                 nk_xlib_shutdown(void);\nNK_API void                 nk_xlib_set_font(XFont*);\nNK_API void                 nk_xlib_push_font(XFont*);\nNK_API void                 nk_xlib_paste(nk_handle, struct nk_text_edit*);\nNK_API void                 nk_xlib_copy(nk_handle, const char*, int len);\n\n/* Image */\n#ifdef NK_XLIB_INCLUDE_STB_IMAGE\nNK_API struct nk_image nk_xsurf_load_image_from_file(char const *filename);\nNK_API struct nk_image nk_xsurf_load_image_from_memory(const void *membuf, nk_uint membufSize);\n#endif\n\n/* Font */\nNK_API XFont*               nk_xfont_create(Display *dpy, const char *name);\nNK_API void                 nk_xfont_del(Display *dpy, XFont *font);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_XLIB_IMPLEMENTATION\n#include <string.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <X11/Xlib.h>\n#include <X11/Xutil.h>\n#include <X11/Xresource.h>\n#include <X11/Xlocale.h>\n#include <X11/Xatom.h>\n\n#ifdef NK_XLIB_USE_XFT\n#include <X11/Xft/Xft.h>\n#endif\n\n#include <sys/time.h>\n#include <unistd.h>\n#include <time.h>\n\n\n#ifdef NK_XLIB_IMPLEMENT_STB_IMAGE\n#define STB_IMAGE_IMPLEMENTATION\n#endif\n\n#ifdef NK_XLIB_INCLUDE_STB_IMAGE\n#include \"../../example/stb_image.h\"\n#endif\n\n\n#ifndef NK_X11_DOUBLE_CLICK_LO\n#define NK_X11_DOUBLE_CLICK_LO 0.02\n#endif\n#ifndef NK_X11_DOUBLE_CLICK_HI\n#define NK_X11_DOUBLE_CLICK_HI 0.20\n#endif\n\ntypedef struct XSurface XSurface;\ntypedef struct XImageWithAlpha XImageWithAlpha;\nstruct XFont {\n    int ascent;\n    int descent;\n    int height;\n#ifdef NK_XLIB_USE_XFT\n    XftFont * ft;\n#else\n    XFontSet set;\n    XFontStruct *xfont;\n#endif\n    struct nk_user_font handle;\n};\nstruct XSurface {\n    GC gc;\n    Display *dpy;\n    int screen;\n    Window root;\n    Drawable drawable;\n    unsigned int w, h;\n#ifdef NK_XLIB_USE_XFT\n    XftDraw * ftdraw;\n#endif\n};\nstruct XImageWithAlpha {\n    XImage* ximage;\n    GC clipMaskGC;\n    Pixmap clipMask;\n};\nstatic struct  {\n    char *clipboard_data;\n    int clipboard_len;\n    struct nk_text_edit* clipboard_target;\n\n    Atom xa_clipboard;\n    Atom xa_targets;\n    Atom xa_text;\n    Atom xa_utf8_string;\n\n    struct nk_context ctx;\n    struct XSurface *surf;\n    Cursor cursor;\n    Display *dpy;\n    Window root;\n#ifdef NK_XLIB_USE_XFT\n    Visual *vis;\n    Colormap cmap;\n#endif\n    double last_button_click;\n    double time_of_last_frame;\n} xlib;\n\nNK_INTERN double\nnk_get_time(void)\n{\n    struct timeval tv;\n    if (gettimeofday(&tv, NULL) < 0) return 0;\n    return ((double)tv.tv_sec + (double)tv.tv_usec/1000000);\n}\n\nNK_INTERN unsigned long\nnk_color_from_byte(const nk_byte *c)\n{\n    unsigned long res = 0;\n    res |= (unsigned long)c[0] << 16;\n    res |= (unsigned long)c[1] << 8;\n    res |= (unsigned long)c[2] << 0;\n    return (res);\n}\n\nNK_INTERN XSurface*\nnk_xsurf_create(int screen, unsigned int w, unsigned int h)\n{\n    XSurface *surface = (XSurface*)calloc(1, sizeof(XSurface));\n    surface->w = w;\n    surface->h = h;\n    surface->dpy = xlib.dpy;\n    surface->screen = screen;\n    surface->root = xlib.root;\n    surface->gc = XCreateGC(xlib.dpy, xlib.root, 0, NULL);\n    XSetLineAttributes(xlib.dpy, surface->gc, 1, LineSolid, CapButt, JoinMiter);\n    surface->drawable = XCreatePixmap(xlib.dpy, xlib.root, w, h,\n        (unsigned int)DefaultDepth(xlib.dpy, screen));\n#ifdef NK_XLIB_USE_XFT\n    surface->ftdraw = XftDrawCreate(xlib.dpy, surface->drawable,\n                                xlib.vis, xlib.cmap);\n#endif\n    return surface;\n}\n\nNK_INTERN void\nnk_xsurf_resize(XSurface *surf, unsigned int w, unsigned int h)\n{\n    if(!surf) return;\n    if (surf->w == w && surf->h == h) return;\n    surf->w = w; surf->h = h;\n    if(surf->drawable) XFreePixmap(surf->dpy, surf->drawable);\n    surf->drawable = XCreatePixmap(surf->dpy, surf->root, w, h,\n        (unsigned int)DefaultDepth(surf->dpy, surf->screen));\n#ifdef NK_XLIB_USE_XFT\n    XftDrawChange(surf->ftdraw, surf->drawable);\n#endif\n}\n\nNK_INTERN void\nnk_xsurf_scissor(XSurface *surf, float x, float y, float w, float h)\n{\n    XRectangle clip_rect;\n    clip_rect.x = (short)(x-1);\n    clip_rect.y = (short)(y-1);\n    clip_rect.width = (unsigned short)(w+2);\n    clip_rect.height = (unsigned short)(h+2);\n    XSetClipRectangles(surf->dpy, surf->gc, 0, 0, &clip_rect, 1, Unsorted);\n\n#ifdef NK_XLIB_USE_XFT\n    XftDrawSetClipRectangles(surf->ftdraw, 0, 0, &clip_rect, 1);\n#endif\n}\n\nNK_INTERN void\nnk_xsurf_stroke_line(XSurface *surf, short x0, short y0, short x1,\n    short y1, unsigned int line_thickness, struct nk_color col)\n{\n    unsigned long c = nk_color_from_byte(&col.r);\n    XSetForeground(surf->dpy, surf->gc, c);\n    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);\n    XDrawLine(surf->dpy, surf->drawable, surf->gc, (int)x0, (int)y0, (int)x1, (int)y1);\n    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);\n}\n\nNK_INTERN void\nnk_xsurf_stroke_rect(XSurface* surf, short x, short y, unsigned short w,\n    unsigned short h, unsigned short r, unsigned short line_thickness, struct nk_color col)\n{\n    unsigned long c = nk_color_from_byte(&col.r);\n    XSetForeground(surf->dpy, surf->gc, c);\n    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);\n    if (r == 0) {XDrawRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h);return;}\n\n    {short xc = x + r;\n    short yc = y + r;\n    short wc = (short)(w - 2 * r);\n    short hc = (short)(h - 2 * r);\n\n    XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y, xc+wc, y);\n    XDrawLine(surf->dpy, surf->drawable, surf->gc, x+w, yc, x+w, yc+hc);\n    XDrawLine(surf->dpy, surf->drawable, surf->gc, xc, y+h, xc+wc, y+h);\n    XDrawLine(surf->dpy, surf->drawable, surf->gc, x, yc, x, yc+hc);\n\n    XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,\n        (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);\n    XDrawArc(surf->dpy, surf->drawable, surf->gc, x, y,\n        (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);\n    XDrawArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,\n        (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);\n    XDrawArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,\n        (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);}\n    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);\n}\n\nNK_INTERN void\nnk_xsurf_fill_rect(XSurface* surf, short x, short y, unsigned short w,\n    unsigned short h, unsigned short r, struct nk_color col)\n{\n    unsigned long c = nk_color_from_byte(&col.r);\n    XSetForeground(surf->dpy, surf->gc, c);\n    if (r == 0) {XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h); return;}\n\n    {short xc = x + r;\n    short yc = y + r;\n    short wc = (short)(w - 2 * r);\n    short hc = (short)(h - 2 * r);\n\n    XPoint pnts[12];\n    pnts[0].x = x;\n    pnts[0].y = yc;\n    pnts[1].x = xc;\n    pnts[1].y = yc;\n    pnts[2].x = xc;\n    pnts[2].y = y;\n\n    pnts[3].x = xc + wc;\n    pnts[3].y = y;\n    pnts[4].x = xc + wc;\n    pnts[4].y = yc;\n    pnts[5].x = x + w;\n    pnts[5].y = yc;\n\n    pnts[6].x = x + w;\n    pnts[6].y = yc + hc;\n    pnts[7].x = xc + wc;\n    pnts[7].y = yc + hc;\n    pnts[8].x = xc + wc;\n    pnts[8].y = y + h;\n\n    pnts[9].x = xc;\n    pnts[9].y = y + h;\n    pnts[10].x = xc;\n    pnts[10].y = yc + hc;\n    pnts[11].x = x;\n    pnts[11].y = yc + hc;\n\n    XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 12, Convex, CoordModeOrigin);\n    XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, y,\n        (unsigned)r*2, (unsigned)r*2, 0 * 64, 90 * 64);\n    XFillArc(surf->dpy, surf->drawable, surf->gc, x, y,\n        (unsigned)r*2, (unsigned)r*2, 90 * 64, 90 * 64);\n    XFillArc(surf->dpy, surf->drawable, surf->gc, x, yc + hc - r,\n        (unsigned)r*2, (unsigned)2*r, 180 * 64, 90 * 64);\n    XFillArc(surf->dpy, surf->drawable, surf->gc, xc + wc - r, yc + hc - r,\n        (unsigned)r*2, (unsigned)2*r, -90 * 64, 90 * 64);}\n}\n\nNK_INTERN void\nnk_xsurf_fill_triangle(XSurface *surf, short x0, short y0, short x1,\n    short y1, short x2, short y2, struct nk_color col)\n{\n    XPoint pnts[3];\n    unsigned long c = nk_color_from_byte(&col.r);\n    pnts[0].x = (short)x0;\n    pnts[0].y = (short)y0;\n    pnts[1].x = (short)x1;\n    pnts[1].y = (short)y1;\n    pnts[2].x = (short)x2;\n    pnts[2].y = (short)y2;\n    XSetForeground(surf->dpy, surf->gc, c);\n    XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 3, Convex, CoordModeOrigin);\n}\n\nNK_INTERN void\nnk_xsurf_stroke_triangle(XSurface *surf, short x0, short y0, short x1,\n    short y1, short x2, short y2, unsigned short line_thickness, struct nk_color col)\n{\n    unsigned long c = nk_color_from_byte(&col.r);\n    XSetForeground(surf->dpy, surf->gc, c);\n    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);\n    XDrawLine(surf->dpy, surf->drawable, surf->gc, x0, y0, x1, y1);\n    XDrawLine(surf->dpy, surf->drawable, surf->gc, x1, y1, x2, y2);\n    XDrawLine(surf->dpy, surf->drawable, surf->gc, x2, y2, x0, y0);\n    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);\n}\n\nNK_INTERN void\nnk_xsurf_fill_polygon(XSurface *surf,  const struct nk_vec2i *pnts, int count,\n    struct nk_color col)\n{\n    int i = 0;\n    #define MAX_POINTS 128\n    XPoint xpnts[MAX_POINTS];\n    unsigned long c = nk_color_from_byte(&col.r);\n    XSetForeground(surf->dpy, surf->gc, c);\n    for (i = 0; i < count && i < MAX_POINTS; ++i) {\n        xpnts[i].x = pnts[i].x;\n        xpnts[i].y = pnts[i].y;\n    }\n    XFillPolygon(surf->dpy, surf->drawable, surf->gc, xpnts, count, Convex, CoordModeOrigin);\n    #undef MAX_POINTS\n}\n\nNK_INTERN void\nnk_xsurf_stroke_polygon(XSurface *surf, const struct nk_vec2i *pnts, int count,\n    unsigned short line_thickness, struct nk_color col)\n{\n    int i = 0;\n    unsigned long c = nk_color_from_byte(&col.r);\n    XSetForeground(surf->dpy, surf->gc, c);\n    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);\n    for (i = 1; i < count; ++i)\n        XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y);\n    XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y);\n    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);\n}\n\nNK_INTERN void\nnk_xsurf_stroke_polyline(XSurface *surf, const struct nk_vec2i *pnts,\n    int count, unsigned short line_thickness, struct nk_color col)\n{\n    int i = 0;\n    unsigned long c = nk_color_from_byte(&col.r);\n    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);\n    XSetForeground(surf->dpy, surf->gc, c);\n    for (i = 0; i < count-1; ++i)\n        XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i].x, pnts[i].y, pnts[i+1].x, pnts[i+1].y);\n    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);\n}\n\nNK_INTERN void\nnk_xsurf_fill_circle(XSurface *surf, short x, short y, unsigned short w,\n    unsigned short h, struct nk_color col)\n{\n    unsigned long c = nk_color_from_byte(&col.r);\n    XSetForeground(surf->dpy, surf->gc, c);\n    XFillArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,\n        (unsigned)w, (unsigned)h, 0, 360 * 64);\n}\n\nNK_INTERN void\nnk_xsurf_stroke_circle(XSurface *surf, short x, short y, unsigned short w,\n    unsigned short h, unsigned short line_thickness, struct nk_color col)\n{\n    unsigned long c = nk_color_from_byte(&col.r);\n    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);\n    XSetForeground(surf->dpy, surf->gc, c);\n    XDrawArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,\n        (unsigned)w, (unsigned)h, 0, 360 * 64);\n    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);\n}\n\nNK_INTERN void\nnk_xsurf_stroke_arc(XSurface *surf, short cx, short cy, unsigned short radius,\n    float a_min, float a_max, unsigned short line_thickness, struct nk_color col)\n{\n    unsigned long c = nk_color_from_byte(&col.r);\n    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);\n    XSetForeground(surf->dpy, surf->gc, c);\n    XDrawArc(surf->dpy, surf->drawable, surf->gc, (int)(cx - radius), (int)(cy - radius),\n        (unsigned)(radius * 2), (unsigned)(radius * 2),\n        (int)(a_min * 180 * 64 / NK_PI), (int)(a_max * 180 * 64 / NK_PI));\n}\n\nNK_INTERN void\nnk_xsurf_fill_arc(XSurface *surf, short cx, short cy, unsigned short radius,\n    float a_min, float a_max, struct nk_color col)\n{\n    unsigned long c = nk_color_from_byte(&col.r);\n    XSetForeground(surf->dpy, surf->gc, c);\n    XFillArc(surf->dpy, surf->drawable, surf->gc, (int)(cx - radius), (int)(cy - radius),\n        (unsigned)(radius * 2), (unsigned)(radius * 2),\n        (int)(a_min * 180 * 64 / NK_PI), (int)(a_max * 180 * 64 / NK_PI));\n}\n\nNK_INTERN void\nnk_xsurf_stroke_curve(XSurface *surf, struct nk_vec2i p1,\n    struct nk_vec2i p2, struct nk_vec2i p3, struct nk_vec2i p4,\n    unsigned int num_segments, unsigned short line_thickness, struct nk_color col)\n{\n    unsigned int i_step;\n    float t_step;\n    struct nk_vec2i last = p1;\n\n    XSetLineAttributes(surf->dpy, surf->gc, line_thickness, LineSolid, CapButt, JoinMiter);\n    num_segments = NK_MAX(num_segments, 1);\n    t_step = 1.0f/(float)num_segments;\n    for (i_step = 1; i_step <= num_segments; ++i_step) {\n        float t = t_step * (float)i_step;\n        float u = 1.0f - t;\n        float w1 = u*u*u;\n        float w2 = 3*u*u*t;\n        float w3 = 3*u*t*t;\n        float w4 = t * t *t;\n        float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x;\n        float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y;\n        nk_xsurf_stroke_line(surf, last.x, last.y, (short)x, (short)y, line_thickness,col);\n        last.x = (short)x; last.y = (short)y;\n    }\n    XSetLineAttributes(surf->dpy, surf->gc, 1, LineSolid, CapButt, JoinMiter);\n}\n\nNK_INTERN void\nnk_xsurf_draw_text(XSurface *surf, short x, short y, const char *text, int len,\n    XFont *font, struct nk_color cfg)\n{\n    int tx, ty;\n#ifdef NK_XLIB_USE_XFT\n    XRenderColor xrc;\n    XftColor color;\n#else\n    unsigned long fg = nk_color_from_byte(&cfg.r);\n#endif\n\n    if(!text || !font || !len) return;\n\n    tx = (int)x;\n    ty = (int)y + font->ascent;\n#ifdef NK_XLIB_USE_XFT\n    xrc.red = cfg.r * 257;\n    xrc.green = cfg.g * 257;\n    xrc.blue = cfg.b * 257;\n    xrc.alpha = cfg.a * 257;\n    XftColorAllocValue(surf->dpy, xlib.vis, xlib.cmap, &xrc, &color);\n    XftDrawStringUtf8(surf->ftdraw, &color, font->ft, tx, ty, (FcChar8*)text, len);\n    XftColorFree(surf->dpy, xlib.vis, xlib.cmap, &color);\n#else\n    XSetForeground(surf->dpy, surf->gc, fg);\n    if(font->set)\n        XmbDrawString(surf->dpy,surf->drawable,font->set,surf->gc,tx,ty,(const char*)text,(int)len);\n    else XDrawString(surf->dpy, surf->drawable, surf->gc, tx, ty, (const char*)text, (int)len);\n#endif\n}\n\n\n#ifdef NK_XLIB_INCLUDE_STB_IMAGE\nNK_INTERN struct nk_image\nnk_stbi_image_to_xsurf(unsigned char *data, int width, int height, int channels) {\n    XSurface *surf = xlib.surf;\n    struct nk_image img;\n    int bpl = channels;\n    long i, isize = width*height*channels;\n    XImageWithAlpha *aimage = (XImageWithAlpha*)calloc( 1, sizeof(XImageWithAlpha) );\n    int depth = DefaultDepth(surf->dpy, surf->screen);\n    if (data == NULL) return nk_image_id(0);\n    if (aimage == NULL) return nk_image_id(0);\n\n    switch (depth){\n        case 24:\n            bpl = 4;\n        break;\n        case 16:\n        case 15:\n            bpl = 2;\n        break;\n        default:\n            bpl = 1;\n        break;\n    }\n\n    /* rgba to bgra */\n    if (channels >= 3){\n        for (i=0; i < isize; i += channels) {\n            unsigned char red  = data[i+2];\n            unsigned char blue = data[i];\n            data[i]   = red;\n            data[i+2] = blue;\n        }\n    }\n\n    if (channels == 4){\n        const unsigned alpha_treshold = 127;\n        aimage->clipMask = XCreatePixmap(surf->dpy, surf->drawable, width, height, 1);\n\n        if( aimage->clipMask ){\n            aimage->clipMaskGC = XCreateGC(surf->dpy, aimage->clipMask, 0, 0);\n            XSetForeground(surf->dpy, aimage->clipMaskGC, BlackPixel(surf->dpy, surf->screen));\n            XFillRectangle(surf->dpy, aimage->clipMask, aimage->clipMaskGC, 0, 0, width, height);\n\n            XSetForeground(surf->dpy, aimage->clipMaskGC, WhitePixel(surf->dpy, surf->screen));\n            for (i=0; i < isize; i += channels){\n                unsigned char alpha = data[i+3];\n                int div = i / channels;\n                int x = div % width;\n                int y = div / width;\n                if( alpha > alpha_treshold )\n                    XDrawPoint(surf->dpy, aimage->clipMask, aimage->clipMaskGC, x, y);\n            }\n        }\n    }\n\n    aimage->ximage = XCreateImage(surf->dpy,\n           CopyFromParent, depth,\n           ZPixmap, 0,\n           (char*)data,\n           width, height,\n           bpl*8, bpl * width);\n    img = nk_image_ptr( (void*)aimage);\n    img.h = height;\n    img.w = width;\n    return img;\n}\n\nNK_API struct nk_image\nnk_xsurf_load_image_from_memory(const void *membuf, nk_uint membufSize)\n{\n    int x,y,n;\n    unsigned char *data;\n    data = stbi_load_from_memory(membuf, membufSize, &x, &y, &n, 0);\n    return nk_stbi_image_to_xsurf(data, x, y, n);\n}\n\nNK_API struct nk_image\nnk_xsurf_load_image_from_file(char const *filename)\n{\n    int x,y,n;\n    unsigned char *data;\n    data = stbi_load(filename, &x, &y, &n, 0);\n    return nk_stbi_image_to_xsurf(data, x, y, n);\n}\n#endif /* NK_XLIB_INCLUDE_STB_IMAGE */\n\nNK_INTERN void\nnk_xsurf_draw_image(XSurface *surf, short x, short y, unsigned short w, unsigned short h,\n    struct nk_image img, struct nk_color col)\n{\n    XImageWithAlpha *aimage = img.handle.ptr;\n\n    NK_UNUSED(col);\n\n    if (aimage){\n        if (aimage->clipMask){\n            XSetClipMask(surf->dpy, surf->gc, aimage->clipMask);\n            XSetClipOrigin(surf->dpy, surf->gc, x, y);\n        }\n        XPutImage(surf->dpy, surf->drawable, surf->gc, aimage->ximage, 0, 0, x, y, w, h);\n        XSetClipMask(surf->dpy, surf->gc, None);\n    }\n}\n\nvoid\nnk_xsurf_image_free(struct nk_image* image)\n{\n    XSurface *surf = xlib.surf;\n    XImageWithAlpha *aimage = image->handle.ptr;\n    if (!aimage) return;\n    XDestroyImage(aimage->ximage);\n    XFreePixmap(surf->dpy, aimage->clipMask);\n    XFreeGC(surf->dpy, aimage->clipMaskGC);\n    free(aimage);\n}\n\n\nNK_INTERN void\nnk_xsurf_clear(XSurface *surf, unsigned long color)\n{\n    XSetForeground(surf->dpy, surf->gc, color);\n    XFillRectangle(surf->dpy, surf->drawable, surf->gc, 0, 0, surf->w, surf->h);\n}\n\nNK_INTERN void\nnk_xsurf_blit(Drawable target, XSurface *surf, unsigned int w, unsigned int h)\n{\n    XCopyArea(surf->dpy, surf->drawable, target, surf->gc, 0, 0, w, h, 0, 0);\n}\n\nNK_INTERN void\nnk_xsurf_del(XSurface *surf)\n{\n#ifdef NK_XLIB_USE_XFT\n    XftDrawDestroy(surf->ftdraw);\n#endif\n    XFreePixmap(surf->dpy, surf->drawable);\n    XFreeGC(surf->dpy, surf->gc);\n    free(surf);\n}\n\nNK_API XFont*\nnk_xfont_create(Display *dpy, const char *name)\n{\n#ifdef NK_XLIB_USE_XFT\n    XFont *font = (XFont*)calloc(1, sizeof(XFont));\n    font->ft = XftFontOpenName(dpy, XDefaultScreen(dpy), name);\n    if (!font->ft) {\n        fprintf(stderr, \"missing font: %s\\n\", name);\n        return font;\n    }\n    font->ascent = font->ft->ascent;\n    font->descent = font->ft->descent;\n    font->height = font->ft->height;\n#else\n    int n;\n    char *def, **missing;\n    XFont *font = (XFont*)calloc(1, sizeof(XFont));\n    font->set = XCreateFontSet(dpy, name, &missing, &n, &def);\n    if(missing) {\n        while(n--)\n            fprintf(stderr, \"missing fontset: %s\\n\", missing[n]);\n        XFreeStringList(missing);\n    }\n    if(font->set) {\n        XFontStruct **xfonts;\n        char **font_names;\n        XExtentsOfFontSet(font->set);\n        n = XFontsOfFontSet(font->set, &xfonts, &font_names);\n        while(n--) {\n            font->ascent = NK_MAX(font->ascent, (*xfonts)->ascent);\n            font->descent = NK_MAX(font->descent,(*xfonts)->descent);\n            xfonts++;\n        }\n    } else {\n        if(!(font->xfont = XLoadQueryFont(dpy, name))\n        && !(font->xfont = XLoadQueryFont(dpy, \"fixed\"))) {\n            free(font);\n            return 0;\n        }\n        font->ascent = font->xfont->ascent;\n        font->descent = font->xfont->descent;\n    }\n    font->height = font->ascent + font->descent;\n#endif\n    return font;\n}\n\nNK_INTERN float\nnk_xfont_get_text_width(nk_handle handle, float height, const char *text, int len)\n{\n    XFont *font = (XFont*)handle.ptr;\n\n#ifdef NK_XLIB_USE_XFT\n    XGlyphInfo g;\n\n    NK_UNUSED(height);\n\n    if(!font || !text)\n        return 0;\n\n    XftTextExtentsUtf8(xlib.dpy, font->ft, (FcChar8*)text, len, &g);\n    return g.xOff;\n#else\n    XRectangle r;\n\n    NK_UNUSED(height);\n\n    if(!font || !text)\n        return 0;\n\n    if(font->set) {\n        XmbTextExtents(font->set, (const char*)text, len, NULL, &r);\n        return (float)r.width;\n    } else{\n        int w = XTextWidth(font->xfont, (const char*)text, len);\n        return (float)w;\n    }\n#endif\n}\n\nNK_API void\nnk_xfont_del(Display *dpy, XFont *font)\n{\n    if(!font) return;\n#ifdef NK_XLIB_USE_XFT\n    XftFontClose(dpy, font->ft);\n#else\n    if(font->set)\n        XFreeFontSet(dpy, font->set);\n    else\n        XFreeFont(dpy, font->xfont);\n#endif\n    free(font);\n}\n\nNK_API struct nk_context*\nnk_xlib_init(XFont *xfont, Display *dpy, int screen, Window root,\n#ifdef NK_XLIB_USE_XFT\n    Visual *vis, Colormap cmap,\n#endif\n    unsigned int w, unsigned int h)\n{\n    struct nk_user_font *font = &xfont->handle;\n    font->userdata = nk_handle_ptr(xfont);\n    font->height = (float)xfont->height;\n    font->width = nk_xfont_get_text_width;\n    xlib.dpy = dpy;\n    xlib.root = root;\n#ifdef NK_XLIB_USE_XFT\n    xlib.vis = vis;\n    xlib.cmap = cmap;\n#endif\n\n    if (!setlocale(LC_ALL,\"\")) return 0;\n    if (!XSupportsLocale()) return 0;\n    if (!XSetLocaleModifiers(\"@im=none\")) return 0;\n\n    xlib.xa_clipboard = XInternAtom(dpy, \"CLIPBOARD\", False);\n    xlib.xa_targets = XInternAtom(dpy, \"TARGETS\", False);\n    xlib.xa_text = XInternAtom(dpy, \"TEXT\", False);\n    xlib.xa_utf8_string = XInternAtom(dpy, \"UTF8_STRING\", False);\n\n    /* create invisible cursor */\n    {static XColor dummy; char data[1] = {0};\n    Pixmap blank = XCreateBitmapFromData(dpy, root, data, 1, 1);\n    if (blank == None) return 0;\n    xlib.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);\n    XFreePixmap(dpy, blank);}\n\n    xlib.surf = nk_xsurf_create(screen, w, h);\n    nk_init_default(&xlib.ctx, font);\n    xlib.time_of_last_frame = nk_get_time();\n    return &xlib.ctx;\n}\n\nNK_API void\nnk_xlib_set_font(XFont *xfont)\n{\n    struct nk_user_font *font = &xfont->handle;\n    font->userdata = nk_handle_ptr(xfont);\n    font->height = (float)xfont->height;\n    font->width = nk_xfont_get_text_width;\n    nk_style_set_font(&xlib.ctx, font);\n}\n\nNK_API void\nnk_xlib_push_font(XFont *xfont)\n{\n    struct nk_user_font *font = &xfont->handle;\n    font->userdata = nk_handle_ptr(xfont);\n    font->height = (float)xfont->height;\n    font->width = nk_xfont_get_text_width;\n    nk_style_push_font(&xlib.ctx, font);\n}\n\nNK_API void\nnk_xlib_paste(nk_handle handle, struct nk_text_edit* edit)\n{\n    NK_UNUSED(handle);\n    /* Paste in X is asynchronous, so can not use a temporary text edit */\n    NK_ASSERT(edit != &xlib.ctx.text_edit && \"Paste not supported for temporary editors\");\n    xlib.clipboard_target = edit;\n    /* Request the contents of the primary buffer */\n    XConvertSelection(xlib.dpy, XA_PRIMARY, XA_STRING, XA_PRIMARY, xlib.root, CurrentTime);\n}\n\nNK_API void\nnk_xlib_copy(nk_handle handle, const char* str, int len)\n{\n    NK_UNUSED(handle);\n    free(xlib.clipboard_data);\n    xlib.clipboard_len = 0;\n    xlib.clipboard_data = malloc((size_t)len);\n    if (xlib.clipboard_data) {\n        memcpy(xlib.clipboard_data, str, (size_t)len);\n        xlib.clipboard_len = len;\n        XSetSelectionOwner(xlib.dpy, XA_PRIMARY, xlib.root, CurrentTime);\n        XSetSelectionOwner(xlib.dpy, xlib.xa_clipboard, xlib.root, CurrentTime);\n    }\n}\n\nNK_API int\nnk_xlib_handle_event(Display *dpy, int screen, Window win, XEvent *evt)\n{\n    struct nk_context *ctx = &xlib.ctx;\n    static int insert_toggle = 0;\n\n    NK_UNUSED(screen);\n\n    /* optional grabbing behavior */\n    if (ctx->input.mouse.grab) {\n        XDefineCursor(xlib.dpy, xlib.root, xlib.cursor);\n        ctx->input.mouse.grab = 0;\n    } else if (ctx->input.mouse.ungrab) {\n        XWarpPointer(xlib.dpy, None, xlib.root, 0, 0, 0, 0,\n            (int)ctx->input.mouse.prev.x, (int)ctx->input.mouse.prev.y);\n        XUndefineCursor(xlib.dpy, xlib.root);\n        ctx->input.mouse.ungrab = 0;\n    }\n\n    if (evt->type == KeyPress || evt->type == KeyRelease)\n    {\n        /* Key handler */\n        int ret, down = (evt->type == KeyPress);\n        KeySym *code = XGetKeyboardMapping(xlib.surf->dpy, (KeyCode)evt->xkey.keycode, 1, &ret);\n        if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down);\n        else if (*code == XK_Control_L || *code == XK_Control_R) nk_input_key(ctx, NK_KEY_CTRL, down);\n        else if (*code == XK_Delete)    nk_input_key(ctx, NK_KEY_DEL, down);\n        else if (*code == XK_Return || *code == XK_KP_Enter)    nk_input_key(ctx, NK_KEY_ENTER, down);\n        else if (*code == XK_Tab)       nk_input_key(ctx, NK_KEY_TAB, down);\n        else if (*code == XK_Left)      nk_input_key(ctx, NK_KEY_LEFT, down);\n        else if (*code == XK_Right)     nk_input_key(ctx, NK_KEY_RIGHT, down);\n        else if (*code == XK_Up)        nk_input_key(ctx, NK_KEY_UP, down);\n        else if (*code == XK_Down)      nk_input_key(ctx, NK_KEY_DOWN, down);\n        else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);\n        else if (*code == XK_Escape)    nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down);\n        else if (*code == XK_Page_Up)   nk_input_key(ctx, NK_KEY_SCROLL_UP, down);\n        else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);\n        else if (*code == XK_Home) {\n            nk_input_key(ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_START, down);\n        } else if (*code == XK_End) {\n            nk_input_key(ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_END, down);\n        } else {\n            if (*code == 'c' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_COPY, down);\n            else if (*code == 'v' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_PASTE, down);\n            else if (*code == 'x' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_CUT, down);\n            else if (*code == 'z' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_UNDO, down);\n            else if (*code == 'r' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_REDO, down);\n            else if (*code == XK_Left && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else if (*code == XK_Right && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else if (*code == 'b' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down);\n            else if (*code == 'e' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down);\n            else if (*code == 'a' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx,NK_KEY_TEXT_SELECT_ALL, down);\n            else if (*code == XK_Insert) {\n                if (down) insert_toggle = !insert_toggle;\n                if (insert_toggle) {\n                    nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);\n                } else {\n                    nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);\n                }\n            } else {\n                if (down) {\n                    char buf[32];\n                    KeySym keysym = 0;\n                    if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)\n                        nk_input_glyph(ctx, buf);\n                }\n            }\n        }\n        XFree(code);\n        return 1;\n    } else if (evt->type == ButtonPress || evt->type == ButtonRelease) {\n        /* Button handler */\n        int down = (evt->type == ButtonPress);\n        const int x = evt->xbutton.x, y = evt->xbutton.y;\n        if (evt->xbutton.button == Button1) {\n            if (down) { /* Double-Click Button handler */\n                float dt = nk_get_time() - xlib.last_button_click;\n                if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI)\n                    nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true);\n                xlib.last_button_click = nk_get_time();\n            } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false);\n            nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);\n        } else if (evt->xbutton.button == Button2)\n            nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);\n        else if (evt->xbutton.button == Button3)\n            nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);\n        else if (evt->xbutton.button == Button4)\n            nk_input_scroll(ctx, nk_vec2(0, 1.0f));\n        else if (evt->xbutton.button == Button5)\n            nk_input_scroll(ctx, nk_vec2(0, -1.0f));\n        else if (evt->xbutton.button == 8)\n            nk_input_button(ctx, NK_BUTTON_X1, x, y, down);\n        else if (evt->xbutton.button == 9)\n            nk_input_button(ctx, NK_BUTTON_X2, x, y, down);\n        else return 0;\n        return 1;\n    } else if (evt->type == MotionNotify) {\n        /* Mouse motion handler */\n        const int x = evt->xmotion.x, y = evt->xmotion.y;\n        nk_input_motion(ctx, x, y);\n        if (ctx->input.mouse.grabbed) {\n            ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n            ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n            XWarpPointer(xlib.dpy, None, xlib.surf->root, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);\n        }\n        return 1;\n    } else if (evt->type == Expose || evt->type == ConfigureNotify) {\n        /* Window resize handler */\n        unsigned int width, height;\n        XWindowAttributes attr;\n        XGetWindowAttributes(dpy, win, &attr);\n        width = (unsigned int)attr.width;\n        height = (unsigned int)attr.height;\n        nk_xsurf_resize(xlib.surf, width, height);\n        return 1;\n    } else if (evt->type == KeymapNotify) {\n        XRefreshKeyboardMapping(&evt->xmapping);\n        return 1;\n    } else if (evt->type == SelectionClear) {\n        free(xlib.clipboard_data);\n        xlib.clipboard_data = NULL;\n        xlib.clipboard_len = 0;\n        return 1;\n    } else if (evt->type == SelectionRequest) {\n        XEvent reply;\n        reply.xselection.type = SelectionNotify;\n        reply.xselection.requestor = evt->xselectionrequest.requestor;\n        reply.xselection.selection = evt->xselectionrequest.selection;\n        reply.xselection.target = evt->xselectionrequest.target;\n        reply.xselection.property = None; /* Default refuse */\n        reply.xselection.time = evt->xselectionrequest.time;\n\n        if (reply.xselection.target == xlib.xa_targets) {\n            Atom target_list[4];\n            target_list[0] = xlib.xa_targets;\n            target_list[1] = xlib.xa_text;\n            target_list[2] = xlib.xa_utf8_string;\n            target_list[3] = XA_STRING;\n\n            reply.xselection.property = evt->xselectionrequest.property;\n            XChangeProperty(evt->xselection.display,evt->xselectionrequest.requestor,\n                reply.xselection.property, XA_ATOM, 32, PropModeReplace,\n                (unsigned char*)&target_list, 4);\n        } else if (xlib.clipboard_data && (reply.xselection.target == xlib.xa_text ||\n            reply.xselection.target == xlib.xa_utf8_string || reply.xselection.target == XA_STRING)) {\n            reply.xselection.property = evt->xselectionrequest.property;\n            XChangeProperty(evt->xselection.display,evt->xselectionrequest.requestor,\n                reply.xselection.property, reply.xselection.target, 8, PropModeReplace,\n                (unsigned char*)xlib.clipboard_data, xlib.clipboard_len);\n        }\n        XSendEvent(evt->xselection.display, evt->xselectionrequest.requestor, True, 0, &reply);\n        XFlush(evt->xselection.display);\n        return 1;\n    } else if (evt->type == SelectionNotify && xlib.clipboard_target) {\n        if ((evt->xselection.target != XA_STRING) &&\n            (evt->xselection.target != xlib.xa_utf8_string) &&\n            (evt->xselection.target != xlib.xa_text))\n            return 1;\n\n        {Atom actual_type;\n        int actual_format;\n        unsigned long pos = 0, len, remain;\n        unsigned char* data = 0;\n        do {\n            XGetWindowProperty(dpy, win, XA_PRIMARY, (int)pos, 1024, False,\n                AnyPropertyType, &actual_type, &actual_format, &len, &remain, &data);\n            if (len && data)\n                nk_textedit_text(xlib.clipboard_target, (char*)data, (int)len);\n            if (data != 0) XFree(data);\n            pos += (len * (unsigned long)actual_format) / 32;\n        } while (remain != 0);}\n        return 1;\n    }\n    return 0;\n}\n\nNK_API void\nnk_xlib_shutdown(void)\n{\n    nk_xsurf_del(xlib.surf);\n    nk_free(&xlib.ctx);\n    XFreeCursor(xlib.dpy, xlib.cursor);\n    memset(&xlib, 0, sizeof(xlib));\n}\n\nNK_API void\nnk_xlib_render(Drawable screen, struct nk_color clear)\n{\n    const struct nk_command *cmd;\n    struct nk_context *ctx = &xlib.ctx;\n    XSurface *surf = xlib.surf;\n\n    double now = nk_get_time();\n    xlib.ctx.delta_time_seconds = now - xlib.time_of_last_frame;\n    xlib.time_of_last_frame = now;\n\n    nk_xsurf_clear(xlib.surf, nk_color_from_byte(&clear.r));\n    nk_foreach(cmd, &xlib.ctx)\n    {\n        switch (cmd->type) {\n        case NK_COMMAND_NOP: break;\n        case NK_COMMAND_SCISSOR: {\n            const struct nk_command_scissor *s =(const struct nk_command_scissor*)cmd;\n            nk_xsurf_scissor(surf, s->x, s->y, s->w, s->h);\n        } break;\n        case NK_COMMAND_LINE: {\n            const struct nk_command_line *l = (const struct nk_command_line *)cmd;\n            nk_xsurf_stroke_line(surf, l->begin.x, l->begin.y, l->end.x,\n                l->end.y, l->line_thickness, l->color);\n        } break;\n        case NK_COMMAND_RECT: {\n            const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;\n            nk_xsurf_stroke_rect(surf, r->x, r->y, NK_MAX(r->w -r->line_thickness, 0),\n                NK_MAX(r->h - r->line_thickness, 0), (unsigned short)r->rounding,\n                r->line_thickness, r->color);\n        } break;\n        case NK_COMMAND_RECT_FILLED: {\n            const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;\n            nk_xsurf_fill_rect(surf, r->x, r->y, r->w, r->h,\n                (unsigned short)r->rounding, r->color);\n        } break;\n        case NK_COMMAND_CIRCLE: {\n            const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;\n            nk_xsurf_stroke_circle(surf, c->x, c->y, c->w, c->h, c->line_thickness, c->color);\n        } break;\n        case NK_COMMAND_CIRCLE_FILLED: {\n            const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;\n            nk_xsurf_fill_circle(surf, c->x, c->y, c->w, c->h, c->color);\n        } break;\n        case NK_COMMAND_ARC: {\n            const struct nk_command_arc *a = (const struct nk_command_arc *)cmd;\n            nk_xsurf_stroke_arc(surf, a->cx, a->cy, a->r, a->a[0], a->a[1], a->line_thickness, a->color);\n        } break;\n        case NK_COMMAND_ARC_FILLED: {\n            const struct nk_command_arc_filled *a = (const struct nk_command_arc_filled *)cmd;\n            nk_xsurf_fill_arc(surf, a->cx, a->cy, a->r, a->a[0], a->a[1], a->color);\n        } break;\n        case NK_COMMAND_TRIANGLE: {\n            const struct nk_command_triangle*t = (const struct nk_command_triangle*)cmd;\n            nk_xsurf_stroke_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y,\n                t->c.x, t->c.y, t->line_thickness, t->color);\n        } break;\n        case NK_COMMAND_TRIANGLE_FILLED: {\n            const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;\n            nk_xsurf_fill_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y,\n                t->c.x, t->c.y, t->color);\n        } break;\n        case NK_COMMAND_POLYGON: {\n            const struct nk_command_polygon *p =(const struct nk_command_polygon*)cmd;\n            nk_xsurf_stroke_polygon(surf, p->points, p->point_count, p->line_thickness,p->color);\n        } break;\n        case NK_COMMAND_POLYGON_FILLED: {\n            const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;\n            nk_xsurf_fill_polygon(surf, p->points, p->point_count, p->color);\n        } break;\n        case NK_COMMAND_POLYLINE: {\n            const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;\n            nk_xsurf_stroke_polyline(surf, p->points, p->point_count, p->line_thickness, p->color);\n        } break;\n        case NK_COMMAND_TEXT: {\n            const struct nk_command_text *t = (const struct nk_command_text*)cmd;\n            nk_xsurf_draw_text(surf, t->x, t->y, (const char*)t->string, t->length,\n                (XFont*)t->font->userdata.ptr, t->foreground);\n        } break;\n        case NK_COMMAND_CURVE: {\n            const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;\n            nk_xsurf_stroke_curve(surf, q->begin, q->ctrl[0], q->ctrl[1],\n                q->end, 22, q->line_thickness, q->color);\n        } break;\n        case NK_COMMAND_IMAGE: {\n            const struct nk_command_image *i = (const struct nk_command_image *)cmd;\n            nk_xsurf_draw_image(surf, i->x, i->y, i->w, i->h, i->img, i->col);\n        } break;\n        case NK_COMMAND_RECT_MULTI_COLOR:\n        case NK_COMMAND_CUSTOM:\n        default: break;\n        }\n    }\n    nk_clear(ctx);\n    nk_xsurf_blit(screen, surf, surf->w, surf->h);\n}\n#endif\n"
  },
  {
    "path": "demo/x11_opengl2/Makefile",
    "content": "# Install\nBIN = demo\n\n# Compiler\nCC ?= clang\nDCC = gcc\n\n# Flags\nCFLAGS += -std=c89 -Wall -Wextra -pedantic\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\n# Modes\n.PHONY: gcc\ngcc: CC ?= gcc\ngcc: $(BIN)\n\n.PHONY: clang\nclang: CC ?= clang\nclang: $(BIN)\n\n$(BIN):\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) -lX11 -lm -lGL -lm -lGLU\n"
  },
  {
    "path": "demo/x11_opengl2/main.c",
    "content": "/* nuklear - v1.32.0 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <time.h>\n#include <limits.h>\n\n#include <GL/glx.h>\n#include <GL/glxext.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_XLIB_GL2_IMPLEMENTATION\n#include \"../../nuklear.h\"\n#include \"nuklear_xlib_gl2.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define MAX_VERTEX_BUFFER 512 * 1024\n#define MAX_ELEMENT_BUFFER 128 * 1024\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nstruct XWindow {\n    Display *dpy;\n    Window win;\n    XVisualInfo *vis;\n    Colormap cmap;\n    XSetWindowAttributes swa;\n    XWindowAttributes attr;\n    GLXFBConfig fbc;\n    Atom wm_delete_window;\n    int width, height;\n};\nstatic int gl_err = nk_false;\nstatic int gl_error_handler(Display *dpy, XErrorEvent *ev)\n{NK_UNUSED(dpy); NK_UNUSED(ev); gl_err = nk_true; return 0;}\n\nstatic void\ndie(const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    fputs(\"\\n\", stderr);\n    exit(EXIT_FAILURE);\n}\n\nstatic int\nhas_extension(const char *string, const char *ext)\n{\n    const char *start, *where, *term;\n    where = strchr(ext, ' ');\n    if (where || *ext == '\\0')\n        return nk_false;\n\n    for (start = string;;) {\n        where = strstr((const char*)start, ext);\n        if (!where) break;\n        term = where + strlen(ext);\n        if (where == start || *(where - 1) == ' ') {\n            if (*term == ' ' || *term == '\\0')\n                return nk_true;\n        }\n        start = term;\n    }\n    return nk_false;\n}\n\nint main(void)\n{\n    /* Platform */\n    int running = 1;\n    struct XWindow win;\n    GLXContext glContext;\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    memset(&win, 0, sizeof(win));\n    win.dpy = XOpenDisplay(NULL);\n    if (!win.dpy) die(\"Failed to open X display\\n\");\n    {\n        /* check glx version */\n        int glx_major, glx_minor;\n        if (!glXQueryVersion(win.dpy, &glx_major, &glx_minor))\n            die(\"[X11]: Error: Failed to query OpenGL version\\n\");\n        if ((glx_major == 1 && glx_minor < 3) || (glx_major < 1))\n            die(\"[X11]: Error: Invalid GLX version!\\n\");\n    }\n    {\n        /* find and pick matching framebuffer visual */\n        int fb_count;\n        static GLint attr[] = {\n            GLX_X_RENDERABLE,   True,\n            GLX_DRAWABLE_TYPE,  GLX_WINDOW_BIT,\n            GLX_RENDER_TYPE,    GLX_RGBA_BIT,\n            GLX_X_VISUAL_TYPE,  GLX_TRUE_COLOR,\n            GLX_RED_SIZE,       8,\n            GLX_GREEN_SIZE,     8,\n            GLX_BLUE_SIZE,      8,\n            GLX_ALPHA_SIZE,     8,\n            GLX_DEPTH_SIZE,     24,\n            GLX_STENCIL_SIZE,   8,\n            GLX_DOUBLEBUFFER,   True,\n            None\n        };\n        GLXFBConfig *fbc;\n        fbc = glXChooseFBConfig(win.dpy, DefaultScreen(win.dpy), attr, &fb_count);\n        if (!fbc) die(\"[X11]: Error: failed to retrieve framebuffer configuration\\n\");\n        {\n            /* pick framebuffer with most samples per pixel */\n            int i;\n            int fb_best = -1, best_num_samples = -1;\n            for (i = 0; i < fb_count; ++i) {\n                XVisualInfo *vi = glXGetVisualFromFBConfig(win.dpy, fbc[i]);\n                if (vi) {\n                    int sample_buffer, samples;\n                    glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLE_BUFFERS, &sample_buffer);\n                    glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLES, &samples);\n                    if ((fb_best < 0) || (sample_buffer && samples > best_num_samples))\n                        fb_best = i, best_num_samples = samples;\n                    XFree(vi);\n                }\n            }\n            win.fbc = fbc[fb_best];\n            XFree(fbc);\n            win.vis = glXGetVisualFromFBConfig(win.dpy, win.fbc);\n        }\n    }\n    {\n        /* create window */\n        win.cmap = XCreateColormap(win.dpy, RootWindow(win.dpy, win.vis->screen), win.vis->visual, AllocNone);\n        win.swa.colormap =  win.cmap;\n        win.swa.background_pixmap = None;\n        win.swa.border_pixel = 0;\n        win.swa.event_mask =\n            ExposureMask | KeyPressMask | KeyReleaseMask |\n            ButtonPress | ButtonReleaseMask| ButtonMotionMask |\n            Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|\n            PointerMotionMask| StructureNotifyMask;\n        win.win = XCreateWindow(win.dpy, RootWindow(win.dpy, win.vis->screen), 0, 0,\n            WINDOW_WIDTH, WINDOW_HEIGHT, 0, win.vis->depth, InputOutput,\n            win.vis->visual, CWBorderPixel|CWColormap|CWEventMask, &win.swa);\n        if (!win.win) die(\"[X11]: Failed to create window\\n\");\n        XFree(win.vis);\n        XStoreName(win.dpy, win.win, \"Demo\");\n        XMapWindow(win.dpy, win.win);\n        win.wm_delete_window = XInternAtom(win.dpy, \"WM_DELETE_WINDOW\", False);\n        XSetWMProtocols(win.dpy, win.win, &win.wm_delete_window, 1);\n    }\n    {\n        /* create opengl context */\n        typedef GLXContext(*glxCreateContext)(Display*, GLXFBConfig, GLXContext, Bool, const int*);\n        int(*old_handler)(Display*, XErrorEvent*) = XSetErrorHandler(gl_error_handler);\n        const char *extensions_str = glXQueryExtensionsString(win.dpy, DefaultScreen(win.dpy));\n        glxCreateContext create_context = (glxCreateContext)\n            glXGetProcAddressARB((const GLubyte*)\"glXCreateContextAttribsARB\");\n\n        gl_err = nk_false;\n        if (!has_extension(extensions_str, \"GLX_ARB_create_context\") || !create_context) {\n            fprintf(stdout, \"[X11]: glXCreateContextAttribARB() not found...\\n\");\n            fprintf(stdout, \"[X11]: ... using old-style GLX context\\n\");\n            glContext = glXCreateNewContext(win.dpy, win.fbc, GLX_RGBA_TYPE, 0, True);\n        } else {\n            GLint attr[] = {\n                GLX_CONTEXT_MAJOR_VERSION_ARB, 2,\n                GLX_CONTEXT_MINOR_VERSION_ARB, 2,\n                None\n            };\n            glContext = create_context(win.dpy, win.fbc, 0, True, attr);\n            XSync(win.dpy, False);\n            if (gl_err || !glContext) {\n                /* Could not create GL 3.0 context. Fallback to old 2.x context.\n                 * If a version below 3.0 is requested, implementations will\n                 * return the newest context version compatible with OpenGL\n                 * version less than version 3.0.*/\n                attr[1] = 1; attr[3] = 0;\n                gl_err = nk_false;\n                fprintf(stdout, \"[X11] Failed to create OpenGL 3.0 context\\n\");\n                fprintf(stdout, \"[X11] ... using old-style GLX context!\\n\");\n                glContext = create_context(win.dpy, win.fbc, 0, True, attr);\n            }\n        }\n        XSync(win.dpy, False);\n        XSetErrorHandler(old_handler);\n        if (gl_err || !glContext)\n            die(\"[X11]: Failed to create an OpenGL context\\n\");\n        glXMakeCurrent(win.dpy, win.win, glContext);\n    }\n\n    ctx = nk_x11_init(win.dpy, win.win);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    /* Load Cursor: if you uncomment cursor loading please hide the cursor */\n    {struct nk_font_atlas *atlas;\n    nk_x11_font_stash_begin(&atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Roboto-Regular.ttf\", 14, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_x11_font_stash_end();\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &droid->handle);*/}\n\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (running)\n    {\n        /* Input */\n        XEvent evt;\n        nk_input_begin(ctx);\n        while (XPending(win.dpy)) {\n            XNextEvent(win.dpy, &evt);\n            if (evt.type == ClientMessage) goto cleanup;\n            if (XFilterEvent(&evt, win.win)) continue;\n            nk_x11_handle_event(&evt);\n        }\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 200, 200),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        XGetWindowAttributes(win.dpy, win.win, &win.attr);\n        glViewport(0, 0, win.width, win.height);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(bg.r, bg.g, bg.b, bg.a);\n        /* IMPORTANT: `nk_x11_render` modifies some global OpenGL state\n         * with blending, scissor, face culling, depth test and viewport and\n         * defaults everything back into a default state.\n         * Make sure to either a.) save and restore or b.) reset your own state after\n         * rendering the UI. */\n        nk_x11_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);\n        glXSwapBuffers(win.dpy, win.win);\n    }\n\ncleanup:\n    nk_x11_shutdown();\n    glXMakeCurrent(win.dpy, 0, 0);\n    glXDestroyContext(win.dpy, glContext);\n    XUnmapWindow(win.dpy, win.win);\n    XFreeColormap(win.dpy, win.cmap);\n    XDestroyWindow(win.dpy, win.win);\n    XCloseDisplay(win.dpy);\n    return 0;\n\n}\n"
  },
  {
    "path": "demo/x11_opengl2/nuklear_xlib_gl2.h",
    "content": "/*\n * Nuklear - 1.32.0 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_XLIB_GL2_H_\n#define NK_XLIB_GL2_H_\n\n#include <X11/Xlib.h>\nNK_API struct nk_context*   nk_x11_init(Display *dpy, Window win);\nNK_API void                 nk_x11_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void                 nk_x11_font_stash_end(void);\nNK_API int                  nk_x11_handle_event(XEvent *evt);\nNK_API void                 nk_x11_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);\nNK_API void                 nk_x11_shutdown(void);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_XLIB_GL2_IMPLEMENTATION\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <sys/time.h>\n#include <unistd.h>\n#include <time.h>\n\n#include <X11/Xlib.h>\n#include <X11/Xutil.h>\n#include <X11/Xresource.h>\n#include <X11/Xlocale.h>\n\n#include <GL/gl.h>\n\n#ifndef NK_X11_DOUBLE_CLICK_LO\n#define NK_X11_DOUBLE_CLICK_LO 0.02\n#endif\n#ifndef NK_X11_DOUBLE_CLICK_HI\n#define NK_X11_DOUBLE_CLICK_HI 0.20\n#endif\n\nstruct nk_x11_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstruct nk_x11_device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint font_tex;\n};\n\nstatic struct nk_x11 {\n    struct nk_x11_device ogl;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    Cursor cursor;\n    Display *dpy;\n    Window win;\n    double last_button_click;\n    double time_of_last_frame;\n} x11;\n\nNK_INTERN double\nnk_get_time(void)\n{\n    struct timeval tv;\n    if (gettimeofday(&tv, NULL) < 0) return 0;\n    return ((double)tv.tv_sec + (double)tv.tv_usec/1000000);\n}\n\nNK_INTERN void\nnk_x11_device_upload_atlas(const void *image, int width, int height)\n{\n    struct nk_x11_device *dev = &x11.ogl;\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nNK_API void\nnk_x11_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)\n{\n    /* setup global state */\n    struct nk_x11_device *dev = &x11.ogl;\n    int width, height;\n    XWindowAttributes attr;\n\n    double now = nk_get_time();\n    x11.ctx.delta_time_seconds = now - x11.time_of_last_frame;\n    x11.time_of_last_frame = now;\n\n    NK_UNUSED(max_vertex_buffer);\n    NK_UNUSED(max_element_buffer);\n\n    XGetWindowAttributes(x11.dpy, x11.win, &attr);\n    width = attr.width;\n    height = attr.height;\n\n    glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glEnable(GL_BLEND);\n    glEnable(GL_TEXTURE_2D);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\n    /* setup viewport/project */\n    glViewport(0,0,(GLsizei)width,(GLsizei)height);\n    glMatrixMode(GL_PROJECTION);\n    glPushMatrix();\n    glLoadIdentity();\n    glOrtho(0.0f, width, height, 0.0f, -1.0f, 1.0f);\n    glMatrixMode(GL_MODELVIEW);\n    glPushMatrix();\n    glLoadIdentity();\n\n    glEnableClientState(GL_VERTEX_ARRAY);\n    glEnableClientState(GL_TEXTURE_COORD_ARRAY);\n    glEnableClientState(GL_COLOR_ARRAY);\n    {\n        GLsizei vs = sizeof(struct nk_x11_vertex);\n        size_t vp = offsetof(struct nk_x11_vertex, position);\n        size_t vt = offsetof(struct nk_x11_vertex, uv);\n        size_t vc = offsetof(struct nk_x11_vertex, col);\n\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        const nk_draw_index *offset = NULL;\n        struct nk_buffer vbuf, ebuf;\n\n        /* fill convert configuration */\n        struct nk_convert_config config;\n        static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n            {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, position)},\n            {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, uv)},\n            {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_x11_vertex, col)},\n            {NK_VERTEX_LAYOUT_END}\n        };\n        memset(&config, 0, sizeof(config));\n        config.vertex_layout = vertex_layout;\n        config.vertex_size = sizeof(struct nk_x11_vertex);\n        config.vertex_alignment = NK_ALIGNOF(struct nk_x11_vertex);\n        config.tex_null = dev->tex_null;\n        config.circle_segment_count = 22;\n        config.curve_segment_count = 22;\n        config.arc_segment_count = 22;\n        config.global_alpha = 1.0f;\n        config.shape_AA = AA;\n        config.line_AA = AA;\n\n        /* convert shapes into vertexes */\n        nk_buffer_init_default(&vbuf);\n        nk_buffer_init_default(&ebuf);\n        nk_convert(&x11.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n\n        /* setup vertex buffer pointer */\n        {const void *vertices = nk_buffer_memory_const(&vbuf);\n        glVertexPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vp));\n        glTexCoordPointer(2, GL_FLOAT, vs, (const void*)((const nk_byte*)vertices + vt));\n        glColorPointer(4, GL_UNSIGNED_BYTE, vs, (const void*)((const nk_byte*)vertices + vc));}\n\n        /* iterate over and execute each draw command */\n        offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);\n        nk_draw_foreach(cmd, &x11.ctx, &dev->cmds)\n        {\n            if (!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor(\n                (GLint)(cmd->clip_rect.x),\n                (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),\n                (GLint)(cmd->clip_rect.w),\n                (GLint)(cmd->clip_rect.h));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(&x11.ctx);\n        nk_buffer_clear(&dev->cmds);\n        nk_buffer_free(&vbuf);\n        nk_buffer_free(&ebuf);\n    }\n\n    /* default OpenGL state */\n    glDisableClientState(GL_VERTEX_ARRAY);\n    glDisableClientState(GL_TEXTURE_COORD_ARRAY);\n    glDisableClientState(GL_COLOR_ARRAY);\n\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glDisable(GL_SCISSOR_TEST);\n    glDisable(GL_BLEND);\n    glDisable(GL_TEXTURE_2D);\n\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glMatrixMode(GL_MODELVIEW);\n    glPopMatrix();\n    glMatrixMode(GL_PROJECTION);\n    glPopMatrix();\n    glPopAttrib();\n\n}\n\nNK_API void\nnk_x11_font_stash_begin(struct nk_font_atlas **atlas)\n{\n    nk_font_atlas_init_default(&x11.atlas);\n    nk_font_atlas_begin(&x11.atlas);\n    *atlas = &x11.atlas;\n}\n\nNK_API void\nnk_x11_font_stash_end(void)\n{\n    const void *image; int w, h;\n    image = nk_font_atlas_bake(&x11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_x11_device_upload_atlas(image, w, h);\n    nk_font_atlas_end(&x11.atlas, nk_handle_id((int)x11.ogl.font_tex), &x11.ogl.tex_null);\n    if (x11.atlas.default_font)\n        nk_style_set_font(&x11.ctx, &x11.atlas.default_font->handle);\n}\n\nNK_API int\nnk_x11_handle_event(XEvent *evt)\n{\n    struct nk_context *ctx = &x11.ctx;\n    static int insert_toggle = 0;\n\n    /* optional grabbing behavior */\n    if (ctx->input.mouse.grab) {\n        XDefineCursor(x11.dpy, x11.win, x11.cursor);\n        ctx->input.mouse.grab = 0;\n    } else if (ctx->input.mouse.ungrab) {\n        XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0,\n            (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);\n        XUndefineCursor(x11.dpy, x11.win);\n        ctx->input.mouse.ungrab = 0;\n    }\n\n    if (evt->type == KeyPress || evt->type == KeyRelease)\n    {\n        /* Key handler */\n        int ret, down = (evt->type == KeyPress);\n        KeySym *code = XGetKeyboardMapping(x11.dpy, (KeyCode)evt->xkey.keycode, 1, &ret);\n        if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down);\n        else if (*code == XK_Control_L || *code == XK_Control_R) nk_input_key(ctx, NK_KEY_CTRL, down);\n        else if (*code == XK_Delete)    nk_input_key(ctx, NK_KEY_DEL, down);\n        else if (*code == XK_Return || *code == XK_KP_Enter)    nk_input_key(ctx, NK_KEY_ENTER, down);\n        else if (*code == XK_Tab)       nk_input_key(ctx, NK_KEY_TAB, down);\n        else if (*code == XK_Left)      nk_input_key(ctx, NK_KEY_LEFT, down);\n        else if (*code == XK_Right)     nk_input_key(ctx, NK_KEY_RIGHT, down);\n        else if (*code == XK_Up)      nk_input_key(ctx, NK_KEY_UP, down);\n        else if (*code == XK_Down)     nk_input_key(ctx, NK_KEY_DOWN, down);\n        else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);\n        else if (*code == XK_Escape)    nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down);\n        else if (*code == XK_Page_Up)   nk_input_key(ctx, NK_KEY_SCROLL_UP, down);\n        else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);\n        else if (*code == XK_Home) {\n            nk_input_key(ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_START, down);\n        } else if (*code == XK_End) {\n            nk_input_key(ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_END, down);\n        } else {\n            if (*code == 'c' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_COPY, down);\n            else if (*code == 'v' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_PASTE, down);\n            else if (*code == 'x' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_CUT, down);\n            else if (*code == 'z' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_UNDO, down);\n            else if (*code == 'r' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_REDO, down);\n            else if (*code == XK_Left && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else if (*code == XK_Right && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else if (*code == 'b' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down);\n            else if (*code == 'e' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down);\n            else if (*code == XK_Insert) {\n                if (down) insert_toggle = !insert_toggle;\n                if (insert_toggle) {\n                    nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);\n                } else {\n                    nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);\n                }\n            } else {\n                if (down) {\n                    char buf[32];\n                    KeySym keysym = 0;\n                    if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)\n                        nk_input_glyph(ctx, buf);\n                }\n            }\n        }\n        XFree(code);\n        return 1;\n    } else if (evt->type == ButtonPress || evt->type == ButtonRelease) {\n        /* Button handler */\n        int down = (evt->type == ButtonPress);\n        const int x = evt->xbutton.x, y = evt->xbutton.y;\n        if (evt->xbutton.button == Button1) {\n            if (down) { /* Double-Click Button handler */\n                float dt = nk_get_time() - x11.last_button_click;\n                if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI)\n                    nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true);\n                x11.last_button_click = nk_get_time();\n            } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false);\n            nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);\n        } else if (evt->xbutton.button == Button2)\n            nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);\n        else if (evt->xbutton.button == Button3)\n            nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);\n        else if (evt->xbutton.button == Button4)\n            nk_input_scroll(ctx, nk_vec2(0,1.0f));\n        else if (evt->xbutton.button == Button5)\n            nk_input_scroll(ctx, nk_vec2(0,-1.0f));\n        else if (evt->xbutton.button == 8)\n            nk_input_button(ctx, NK_BUTTON_X1, x, y, down);\n        else if (evt->xbutton.button == 9)\n            nk_input_button(ctx, NK_BUTTON_X2, x, y, down);\n        else return 0;\n        return 1;\n    } else if (evt->type == MotionNotify) {\n        /* Mouse motion handler */\n        const int x = evt->xmotion.x, y = evt->xmotion.y;\n        nk_input_motion(ctx, x, y);\n        if (ctx->input.mouse.grabbed) {\n            ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n            ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n            XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);\n        }\n        return 1;\n    } else if (evt->type == KeymapNotify) {\n        XRefreshKeyboardMapping(&evt->xmapping);\n        return 1;\n    }\n    return 0;\n}\n\nNK_API struct nk_context*\nnk_x11_init(Display *dpy, Window win)\n{\n    x11.dpy = dpy;\n    x11.win = win;\n\n    if (!setlocale(LC_ALL,\"\")) return 0;\n    if (!XSupportsLocale()) return 0;\n    if (!XSetLocaleModifiers(\"@im=none\")) return 0;\n\n    /* create invisible cursor */\n    {static XColor dummy; char data[1] = {0};\n    Pixmap blank = XCreateBitmapFromData(dpy, win, data, 1, 1);\n    if (blank == None) return 0;\n    x11.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);\n    XFreePixmap(dpy, blank);}\n\n    nk_buffer_init_default(&x11.ogl.cmds);\n    nk_init_default(&x11.ctx, 0);\n    x11.time_of_last_frame = nk_get_time();\n    return &x11.ctx;\n}\n\nNK_API void\nnk_x11_shutdown(void)\n{\n    struct nk_x11_device *dev = &x11.ogl;\n    nk_font_atlas_clear(&x11.atlas);\n    nk_free(&x11.ctx);\n    glDeleteTextures(1, &dev->font_tex);\n    nk_buffer_free(&dev->cmds);\n    XFreeCursor(x11.dpy, x11.cursor);\n    memset(&x11, 0, sizeof(x11));\n}\n\n#endif\n"
  },
  {
    "path": "demo/x11_opengl3/Makefile",
    "content": "# Install\nBIN = demo\n\n# Compiler\nCC ?= clang\nDCC = gcc\n\n# Flags\nCFLAGS += -std=c89 -Wall -Wextra -pedantic\n\nSRC = main.c\nOBJ = $(SRC:.c=.o)\n\n# Modes\n.PHONY: gcc\ngcc: CC ?= gcc\ngcc: $(BIN)\n\n.PHONY: clang\nclang: CC ?= clang\nclang: $(BIN)\n\n$(BIN):\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) -lX11 -lm -lGL -lm -lGLU\n"
  },
  {
    "path": "demo/x11_opengl3/main.c",
    "content": "/* nuklear - v1.32.0 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <time.h>\n#include <limits.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#define NK_XLIB_GL3_IMPLEMENTATION\n#define NK_XLIB_LOAD_OPENGL_EXTENSIONS\n#include \"../../nuklear.h\"\n#include \"nuklear_xlib_gl3.h\"\n\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define MAX_VERTEX_BUFFER 512 * 1024\n#define MAX_ELEMENT_BUFFER 128 * 1024\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n/*#define INCLUDE_CANVAS */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_CANVAS\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_NODE_EDITOR\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../../demo/common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../../demo/common/calculator.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../../demo/common/canvas.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../../demo/common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../../demo/common/node_editor.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nstruct XWindow {\n    Display *dpy;\n    Window win;\n    XVisualInfo *vis;\n    Colormap cmap;\n    XSetWindowAttributes swa;\n    XWindowAttributes attr;\n    GLXFBConfig fbc;\n    Atom wm_delete_window;\n    int width, height;\n};\nstatic int gl_err = nk_false;\nstatic int gl_error_handler(Display *dpy, XErrorEvent *ev)\n{NK_UNUSED(dpy); NK_UNUSED(ev); gl_err = nk_true;return 0;}\n\nstatic void\ndie(const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    fputs(\"\\n\", stderr);\n    exit(EXIT_FAILURE);\n}\n\nstatic int\nhas_extension(const char *string, const char *ext)\n{\n    const char *start, *where, *term;\n    where = strchr(ext, ' ');\n    if (where || *ext == '\\0')\n        return nk_false;\n\n    for (start = string;;) {\n        where = strstr((const char*)start, ext);\n        if (!where) break;\n        term = where + strlen(ext);\n        if (where == start || *(where - 1) == ' ') {\n            if (*term == ' ' || *term == '\\0')\n                return nk_true;\n        }\n        start = term;\n    }\n    return nk_false;\n}\n\nint main(void)\n{\n    /* Platform */\n    int running = 1;\n    struct XWindow win;\n    GLXContext glContext;\n    struct nk_context *ctx;\n    struct nk_colorf bg;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    memset(&win, 0, sizeof(win));\n    win.dpy = XOpenDisplay(NULL);\n    if (!win.dpy) die(\"Failed to open X display\\n\");\n    {\n        /* check glx version */\n        int glx_major, glx_minor;\n        if (!glXQueryVersion(win.dpy, &glx_major, &glx_minor))\n            die(\"[X11]: Error: Failed to query OpenGL version\\n\");\n        if ((glx_major == 1 && glx_minor < 3) || (glx_major < 1))\n            die(\"[X11]: Error: Invalid GLX version!\\n\");\n    }\n    {\n        /* find and pick matching framebuffer visual */\n        int fb_count;\n        static GLint attr[] = {\n            GLX_X_RENDERABLE,   True,\n            GLX_DRAWABLE_TYPE,  GLX_WINDOW_BIT,\n            GLX_RENDER_TYPE,    GLX_RGBA_BIT,\n            GLX_X_VISUAL_TYPE,  GLX_TRUE_COLOR,\n            GLX_RED_SIZE,       8,\n            GLX_GREEN_SIZE,     8,\n            GLX_BLUE_SIZE,      8,\n            GLX_ALPHA_SIZE,     8,\n            GLX_DEPTH_SIZE,     24,\n            GLX_STENCIL_SIZE,   8,\n            GLX_DOUBLEBUFFER,   True,\n            None\n        };\n        GLXFBConfig *fbc;\n        fbc = glXChooseFBConfig(win.dpy, DefaultScreen(win.dpy), attr, &fb_count);\n        if (!fbc) die(\"[X11]: Error: failed to retrieve framebuffer configuration\\n\");\n        {\n            /* pick framebuffer with most samples per pixel */\n            int i;\n            int fb_best = -1, best_num_samples = -1;\n            for (i = 0; i < fb_count; ++i) {\n                XVisualInfo *vi = glXGetVisualFromFBConfig(win.dpy, fbc[i]);\n                if (vi) {\n                    int sample_buffer, samples;\n                    glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLE_BUFFERS, &sample_buffer);\n                    glXGetFBConfigAttrib(win.dpy, fbc[i], GLX_SAMPLES, &samples);\n                    if ((fb_best < 0) || (sample_buffer && samples > best_num_samples))\n                        fb_best = i, best_num_samples = samples;\n                    XFree(vi);\n                }\n            }\n            win.fbc = fbc[fb_best];\n            XFree(fbc);\n            win.vis = glXGetVisualFromFBConfig(win.dpy, win.fbc);\n        }\n    }\n    {\n        /* create window */\n        win.cmap = XCreateColormap(win.dpy, RootWindow(win.dpy, win.vis->screen), win.vis->visual, AllocNone);\n        win.swa.colormap =  win.cmap;\n        win.swa.background_pixmap = None;\n        win.swa.border_pixel = 0;\n        win.swa.event_mask =\n            ExposureMask | KeyPressMask | KeyReleaseMask |\n            ButtonPress | ButtonReleaseMask| ButtonMotionMask |\n            Button1MotionMask | Button3MotionMask | Button4MotionMask | Button5MotionMask|\n            PointerMotionMask| StructureNotifyMask;\n        win.win = XCreateWindow(win.dpy, RootWindow(win.dpy, win.vis->screen), 0, 0,\n            WINDOW_WIDTH, WINDOW_HEIGHT, 0, win.vis->depth, InputOutput,\n            win.vis->visual, CWBorderPixel|CWColormap|CWEventMask, &win.swa);\n        if (!win.win) die(\"[X11]: Failed to create window\\n\");\n        XFree(win.vis);\n        XStoreName(win.dpy, win.win, \"Demo\");\n        XMapWindow(win.dpy, win.win);\n        win.wm_delete_window = XInternAtom(win.dpy, \"WM_DELETE_WINDOW\", False);\n        XSetWMProtocols(win.dpy, win.win, &win.wm_delete_window, 1);\n    }\n    {\n        /* create opengl context */\n        typedef GLXContext(*glxCreateContext)(Display*, GLXFBConfig, GLXContext, Bool, const int*);\n        int(*old_handler)(Display*, XErrorEvent*) = XSetErrorHandler(gl_error_handler);\n        const char *extensions_str = glXQueryExtensionsString(win.dpy, DefaultScreen(win.dpy));\n        glxCreateContext create_context = (glxCreateContext)\n            glXGetProcAddressARB((const GLubyte*)\"glXCreateContextAttribsARB\");\n\n        gl_err = nk_false;\n        if (!has_extension(extensions_str, \"GLX_ARB_create_context\") || !create_context) {\n            fprintf(stdout, \"[X11]: glXCreateContextAttribARB() not found...\\n\");\n            fprintf(stdout, \"[X11]: ... using old-style GLX context\\n\");\n            glContext = glXCreateNewContext(win.dpy, win.fbc, GLX_RGBA_TYPE, 0, True);\n        } else {\n            GLint attr[] = {\n                GLX_CONTEXT_MAJOR_VERSION_ARB, 3,\n                GLX_CONTEXT_MINOR_VERSION_ARB, 0,\n                None\n            };\n            glContext = create_context(win.dpy, win.fbc, 0, True, attr);\n            XSync(win.dpy, False);\n            if (gl_err || !glContext) {\n                /* Could not create GL 3.0 context. Fallback to old 2.x context.\n                 * If a version below 3.0 is requested, implementations will\n                 * return the newest context version compatible with OpenGL\n                 * version less than version 3.0.*/\n                attr[1] = 1; attr[3] = 0;\n                gl_err = nk_false;\n                fprintf(stdout, \"[X11] Failed to create OpenGL 3.0 context\\n\");\n                fprintf(stdout, \"[X11] ... using old-style GLX context!\\n\");\n                glContext = create_context(win.dpy, win.fbc, 0, True, attr);\n            }\n        }\n        XSync(win.dpy, False);\n        XSetErrorHandler(old_handler);\n        if (gl_err || !glContext)\n            die(\"[X11]: Failed to create an OpenGL context\\n\");\n        glXMakeCurrent(win.dpy, win.win, glContext);\n    }\n\n    ctx = nk_x11_init(win.dpy, win.win);\n    /* Load Fonts: if none of these are loaded a default font will be used  */\n    {struct nk_font_atlas *atlas;\n    nk_x11_font_stash_begin(&atlas);\n    /*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/DroidSans.ttf\", 14, 0);*/\n    /*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Roboto-Regular.ttf\", 14, 0);*/\n    /*struct nk_font *future = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/kenvector_future_thin.ttf\", 13, 0);*/\n    /*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyClean.ttf\", 12, 0);*/\n    /*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/ProggyTiny.ttf\", 10, 0);*/\n    /*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, \"../../../extra_font/Cousine-Regular.ttf\", 13, 0);*/\n    nk_x11_font_stash_end();\n    /*nk_style_load_all_cursors(ctx, atlas->cursors);*/\n    /*nk_style_set_font(ctx, &droid->handle);*/}\n\n    bg.r = 0.10f, bg.g = 0.18f, bg.b = 0.24f, bg.a = 1.0f;\n    while (running)\n    {\n        /* Input */\n        XEvent evt;\n        nk_input_begin(ctx);\n        while (XPending(win.dpy)) {\n            XNextEvent(win.dpy, &evt);\n            if (evt.type == ClientMessage) goto cleanup;\n            if (XFilterEvent(&evt, win.win)) continue;\n            nk_x11_handle_event(&evt);\n        }\n        nk_input_end(ctx);\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 200, 200),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n\n            nk_layout_row_dynamic(ctx, 20, 1);\n            nk_label(ctx, \"background:\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(ctx, 25, 1);\n            if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {\n                nk_layout_row_dynamic(ctx, 120, 1);\n                bg = nk_color_picker(ctx, bg, NK_RGBA);\n                nk_layout_row_dynamic(ctx, 25, 1);\n                bg.r = nk_propertyf(ctx, \"#R:\", 0, bg.r, 1.0f, 0.01f,0.005f);\n                bg.g = nk_propertyf(ctx, \"#G:\", 0, bg.g, 1.0f, 0.01f,0.005f);\n                bg.b = nk_propertyf(ctx, \"#B:\", 0, bg.b, 1.0f, 0.01f,0.005f);\n                bg.a = nk_propertyf(ctx, \"#A:\", 0, bg.a, 1.0f, 0.01f,0.005f);\n                nk_combo_end(ctx);\n            }\n        }\n        nk_end(ctx);\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n          calculator(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n          canvas(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n          overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n          node_editor(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Draw */\n        XGetWindowAttributes(win.dpy, win.win, &win.attr);\n        glViewport(0, 0, win.width, win.height);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(bg.r, bg.g, bg.b, bg.a);\n        /* IMPORTANT: `nk_x11_render` modifies some global OpenGL state\n         * with blending, scissor, face culling, depth test and viewport and\n         * defaults everything back into a default state.\n         * Make sure to either a.) save and restore or b.) reset your own state after\n         * rendering the UI. */\n        nk_x11_render(NK_ANTI_ALIASING_ON, MAX_VERTEX_BUFFER, MAX_ELEMENT_BUFFER);\n        glXSwapBuffers(win.dpy, win.win);\n    }\n\ncleanup:\n    nk_x11_shutdown();\n    glXMakeCurrent(win.dpy, 0, 0);\n    glXDestroyContext(win.dpy, glContext);\n    XUnmapWindow(win.dpy, win.win);\n    XFreeColormap(win.dpy, win.cmap);\n    XDestroyWindow(win.dpy, win.win);\n    XCloseDisplay(win.dpy);\n    return 0;\n\n}\n"
  },
  {
    "path": "demo/x11_opengl3/nuklear_xlib_gl3.h",
    "content": "/*\n * Nuklear - v1.17 - public domain\n * no warrenty implied; use at your own risk.\n * authored from 2015-2016 by Micha Mettke\n */\n/*\n * ==============================================================\n *\n *                              API\n *\n * ===============================================================\n */\n#ifndef NK_XLIB_GL3_H_\n#define NK_XLIB_GL3_H_\n\n#include <X11/Xlib.h>\nNK_API struct nk_context*   nk_x11_init(Display *dpy, Window win);\nNK_API void                 nk_x11_font_stash_begin(struct nk_font_atlas **atlas);\nNK_API void                 nk_x11_font_stash_end(void);\nNK_API int                  nk_x11_handle_event(XEvent *evt);\nNK_API void                 nk_x11_render(enum nk_anti_aliasing, int max_vertex_buffer, int max_element_buffer);\nNK_API void                 nk_x11_shutdown(void);\nNK_API int                  nk_x11_device_create(void);\nNK_API void                 nk_x11_device_destroy(void);\n\n#endif\n/*\n * ==============================================================\n *\n *                          IMPLEMENTATION\n *\n * ===============================================================\n */\n#ifdef NK_XLIB_GL3_IMPLEMENTATION\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include <sys/time.h>\n#include <unistd.h>\n#include <time.h>\n\n#include <X11/Xlib.h>\n#include <X11/Xutil.h>\n#include <X11/Xresource.h>\n#include <X11/Xlocale.h>\n\n#include <GL/gl.h>\n#include <GL/glx.h>\n\n#ifndef NK_X11_DOUBLE_CLICK_LO\n#define NK_X11_DOUBLE_CLICK_LO 0.02\n#endif\n#ifndef NK_X11_DOUBLE_CLICK_HI\n#define NK_X11_DOUBLE_CLICK_HI 0.20\n#endif\n\n#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS\n#include <GL/glxext.h>\n\n/* GL_ARB_vertex_buffer_object */\ntypedef void(*nkglGenBuffers)(GLsizei, GLuint*);\ntypedef void(*nkglBindBuffer)(GLenum, GLuint);\ntypedef void(*nkglBufferData)(GLenum, GLsizeiptr, const GLvoid*, GLenum);\ntypedef void(*nkglBufferSubData)(GLenum, GLintptr, GLsizeiptr, const GLvoid*);\ntypedef void*(*nkglMapBuffer)(GLenum, GLenum);\ntypedef GLboolean(*nkglUnmapBuffer)(GLenum);\ntypedef void(*nkglDeleteBuffers)(GLsizei, GLuint*);\n/* GL_ARB_vertex_array_object */\ntypedef void (*nkglGenVertexArrays)(GLsizei, GLuint*);\ntypedef void (*nkglBindVertexArray)(GLuint);\ntypedef void (*nkglDeleteVertexArrays)(GLsizei, const GLuint*);\n/* GL_ARB_vertex_program / GL_ARB_fragment_program */\ntypedef void(*nkglVertexAttribPointer)(GLuint, GLint, GLenum, GLboolean, GLsizei, const GLvoid*);\ntypedef void(*nkglEnableVertexAttribArray)(GLuint);\ntypedef void(*nkglDisableVertexAttribArray)(GLuint);\n/* GL_ARB_framebuffer_object */\ntypedef void(*nkglGenerateMipmap)(GLenum target);\n/* GLSL/OpenGL 2.0 core */\ntypedef GLuint(*nkglCreateShader)(GLenum);\ntypedef void(*nkglShaderSource)(GLuint, GLsizei, const GLchar**, const GLint*);\ntypedef void(*nkglCompileShader)(GLuint);\ntypedef void(*nkglGetShaderiv)(GLuint, GLenum, GLint*);\ntypedef void(*nkglGetShaderInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*);\ntypedef void(*nkglDeleteShader)(GLuint);\ntypedef GLuint(*nkglCreateProgram)(void);\ntypedef void(*nkglAttachShader)(GLuint, GLuint);\ntypedef void(*nkglDetachShader)(GLuint, GLuint);\ntypedef void(*nkglLinkProgram)(GLuint);\ntypedef void(*nkglUseProgram)(GLuint);\ntypedef void(*nkglGetProgramiv)(GLuint, GLenum, GLint*);\ntypedef void(*nkglGetProgramInfoLog)(GLuint, GLsizei, GLsizei*, GLchar*);\ntypedef void(*nkglDeleteProgram)(GLuint);\ntypedef GLint(*nkglGetUniformLocation)(GLuint, const GLchar*);\ntypedef GLint(*nkglGetAttribLocation)(GLuint, const GLchar*);\ntypedef void(*nkglUniform1i)(GLint, GLint);\ntypedef void(*nkglUniform1f)(GLint, GLfloat);\ntypedef void(*nkglUniformMatrix3fv)(GLint, GLsizei, GLboolean, const GLfloat*);\ntypedef void(*nkglUniformMatrix4fv)(GLint, GLsizei, GLboolean, const GLfloat*);\n\nstatic nkglGenBuffers glGenBuffers;\nstatic nkglBindBuffer glBindBuffer;\nstatic nkglBufferData glBufferData;\nstatic nkglBufferSubData glBufferSubData;\nstatic nkglMapBuffer glMapBuffer;\nstatic nkglUnmapBuffer glUnmapBuffer;\nstatic nkglDeleteBuffers glDeleteBuffers;\nstatic nkglGenVertexArrays glGenVertexArrays;\nstatic nkglBindVertexArray glBindVertexArray;\nstatic nkglDeleteVertexArrays glDeleteVertexArrays;\nstatic nkglVertexAttribPointer glVertexAttribPointer;\nstatic nkglEnableVertexAttribArray glEnableVertexAttribArray;\nstatic nkglDisableVertexAttribArray glDisableVertexAttribArray;\nstatic nkglGenerateMipmap glGenerateMipmap;\nstatic nkglCreateShader glCreateShader;\nstatic nkglShaderSource glShaderSource;\nstatic nkglCompileShader glCompileShader;\nstatic nkglGetShaderiv glGetShaderiv;\nstatic nkglGetShaderInfoLog glGetShaderInfoLog;\nstatic nkglDeleteShader glDeleteShader;\nstatic nkglCreateProgram glCreateProgram;\nstatic nkglAttachShader glAttachShader;\nstatic nkglDetachShader glDetachShader;\nstatic nkglLinkProgram glLinkProgram;\nstatic nkglUseProgram glUseProgram;\nstatic nkglGetProgramiv glGetProgramiv;\nstatic nkglGetProgramInfoLog glGetProgramInfoLog;\nstatic nkglDeleteProgram glDeleteProgram;\nstatic nkglGetUniformLocation glGetUniformLocation;\nstatic nkglGetAttribLocation glGetAttribLocation;\nstatic nkglUniform1i glUniform1i;\nstatic nkglUniform1f glUniform1f;\nstatic nkglUniformMatrix3fv glUniformMatrix3fv;\nstatic nkglUniformMatrix4fv glUniformMatrix4fv;\n\nenum graphics_card_vendors {\n    VENDOR_UNKNOWN,\n    VENDOR_NVIDIA,\n    VENDOR_AMD,\n    VENDOR_INTEL\n};\n\nstruct opengl_info {\n    /* info */\n    const char *vendor_str;\n    const char *version_str;\n    const char *extensions_str;\n    const char *renderer_str;\n    const char *glsl_version_str;\n    enum graphics_card_vendors vendor;\n    /* version */\n    float version;\n    int major_version;\n    int minor_version;\n    /* extensions */\n    int glsl_available;\n    int vertex_buffer_obj_available;\n    int vertex_array_obj_available;\n    int map_buffer_range_available;\n    int fragment_program_available;\n    int frame_buffer_object_available;\n};\n#endif\n\nstruct nk_x11_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstruct nk_x11_device {\n#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS\n    struct opengl_info info;\n#endif\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint vbo, vao, ebo;\n    GLuint prog;\n    GLuint vert_shdr;\n    GLuint frag_shdr;\n    GLint attrib_pos;\n    GLint attrib_uv;\n    GLint attrib_col;\n    GLint uniform_tex;\n    GLint uniform_proj;\n    GLuint font_tex;\n};\n\nstatic struct nk_x11 {\n    struct nk_x11_device ogl;\n    struct nk_context ctx;\n    struct nk_font_atlas atlas;\n    Cursor cursor;\n    Display *dpy;\n    Window win;\n    double last_button_click;\n    double time_of_last_frame;\n} x11;\n\n#ifdef __APPLE__\n  #define NK_SHADER_VERSION \"#version 150\\n\"\n#else\n  #define NK_SHADER_VERSION \"#version 300 es\\n\"\n#endif\n\n#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS\n#include <GL/glx.h>\n\nNK_INTERN double\nnk_get_time(void)\n{\n    struct timeval tv;\n    if (gettimeofday(&tv, NULL) < 0) return 0;\n    return ((double)tv.tv_sec + (double)tv.tv_usec/1000000);\n}\n\nNK_INTERN int\nnk_x11_stricmpn(const char *a, const char *b, int len)\n{\n    int i = 0;\n    for (i = 0; i < len && a[i] && b[i]; ++i)\n        if (a[i] != b[i]) return 1;\n    if (i != len) return 1;\n    return 0;\n}\n\nNK_INTERN int\nnk_x11_check_extension(struct opengl_info *GL, const char *ext)\n{\n    const char *start, *where, *term;\n    where = strchr(ext, ' ');\n    if (where || *ext == '\\0')\n        return nk_false;\n\n    for (start = GL->extensions_str;;) {\n        where = strstr((const char*)start, ext);\n        if (!where) break;\n        term = where + strlen(ext);\n        if (where == start || *(where - 1) == ' ') {\n            if (*term == ' ' || *term == '\\0')\n                return nk_true;\n        }\n        start = term;\n    }\n    return nk_false;\n}\n\n#define GL_EXT(name) (nk##name)nk_gl_ext(#name)\nNK_INTERN __GLXextFuncPtr\nnk_gl_ext(const char *name)\n{\n    __GLXextFuncPtr func;\n    func = glXGetProcAddress((const GLubyte*)name);\n    if (!func) {\n        fprintf(stdout, \"[GL]: failed to load extension: %s\", name);\n        return NULL;\n    }\n    return func;\n}\n\nNK_INTERN int\nnk_load_opengl(struct opengl_info *gl)\n{\n    int failed = nk_false;\n    gl->version_str = (const char*)glGetString(GL_VERSION);\n    glGetIntegerv(GL_MAJOR_VERSION, &gl->major_version);\n    glGetIntegerv(GL_MINOR_VERSION, &gl->minor_version);\n    if (gl->major_version < 2) {\n        fprintf(stderr, \"[GL]: Graphics card does not fulfill minimum OpenGL 2.0 support\\n\");\n        return 0;\n    }\n    gl->version = (float)gl->major_version + (float)gl->minor_version * 0.1f;\n    gl->renderer_str = (const char*)glGetString(GL_RENDERER);\n    gl->extensions_str = (const char*)glGetString(GL_EXTENSIONS);\n    gl->glsl_version_str = (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION);\n    gl->vendor_str = (const char*)glGetString(GL_VENDOR);\n    if (!nk_x11_stricmpn(gl->vendor_str, \"ATI\", 4) ||\n        !nk_x11_stricmpn(gl->vendor_str, \"AMD\", 4))\n        gl->vendor = VENDOR_AMD;\n    else if (!nk_x11_stricmpn(gl->vendor_str, \"NVIDIA\", 6))\n        gl->vendor = VENDOR_NVIDIA;\n    else if (!nk_x11_stricmpn(gl->vendor_str, \"Intel\", 5))\n        gl->vendor = VENDOR_INTEL;\n    else gl->vendor = VENDOR_UNKNOWN;\n\n    /* Extensions */\n    gl->glsl_available = (gl->version >= 2.0f);\n    if (gl->glsl_available) {\n        /* GLSL core in OpenGL > 2 */\n        glCreateShader = GL_EXT(glCreateShader);\n        glShaderSource = GL_EXT(glShaderSource);\n        glCompileShader = GL_EXT(glCompileShader);\n        glGetShaderiv = GL_EXT(glGetShaderiv);\n        glGetShaderInfoLog = GL_EXT(glGetShaderInfoLog);\n        glDeleteShader = GL_EXT(glDeleteShader);\n        glCreateProgram = GL_EXT(glCreateProgram);\n        glAttachShader = GL_EXT(glAttachShader);\n        glDetachShader = GL_EXT(glDetachShader);\n        glLinkProgram = GL_EXT(glLinkProgram);\n        glUseProgram = GL_EXT(glUseProgram);\n        glGetProgramiv = GL_EXT(glGetProgramiv);\n        glGetProgramInfoLog = GL_EXT(glGetProgramInfoLog);\n        glDeleteProgram = GL_EXT(glDeleteProgram);\n        glGetUniformLocation = GL_EXT(glGetUniformLocation);\n        glGetAttribLocation = GL_EXT(glGetAttribLocation);\n        glUniform1i = GL_EXT(glUniform1i);\n        glUniform1f = GL_EXT(glUniform1f);\n        glUniformMatrix3fv = GL_EXT(glUniformMatrix3fv);\n        glUniformMatrix4fv = GL_EXT(glUniformMatrix4fv);\n    }\n    gl->vertex_buffer_obj_available = nk_x11_check_extension(gl, \"GL_ARB_vertex_buffer_object\");\n    if (gl->vertex_buffer_obj_available) {\n        /* GL_ARB_vertex_buffer_object */\n        glGenBuffers = GL_EXT(glGenBuffers);\n        glBindBuffer = GL_EXT(glBindBuffer);\n        glBufferData = GL_EXT(glBufferData);\n        glBufferSubData = GL_EXT(glBufferSubData);\n        glMapBuffer = GL_EXT(glMapBuffer);\n        glUnmapBuffer = GL_EXT(glUnmapBuffer);\n        glDeleteBuffers = GL_EXT(glDeleteBuffers);\n    }\n    gl->fragment_program_available = nk_x11_check_extension(gl, \"GL_ARB_fragment_program\");\n    if (gl->fragment_program_available) {\n        /* GL_ARB_vertex_program / GL_ARB_fragment_program  */\n        glVertexAttribPointer = GL_EXT(glVertexAttribPointer);\n        glEnableVertexAttribArray = GL_EXT(glEnableVertexAttribArray);\n        glDisableVertexAttribArray = GL_EXT(glDisableVertexAttribArray);\n    }\n    gl->vertex_array_obj_available = nk_x11_check_extension(gl, \"GL_ARB_vertex_array_object\");\n    if (gl->vertex_array_obj_available) {\n        /* GL_ARB_vertex_array_object */\n        glGenVertexArrays = GL_EXT(glGenVertexArrays);\n        glBindVertexArray = GL_EXT(glBindVertexArray);\n        glDeleteVertexArrays = GL_EXT(glDeleteVertexArrays);\n    }\n    gl->frame_buffer_object_available = nk_x11_check_extension(gl, \"GL_ARB_framebuffer_object\");\n    if (gl->frame_buffer_object_available) {\n        /* GL_ARB_framebuffer_object */\n        glGenerateMipmap = GL_EXT(glGenerateMipmap);\n    }\n    if (!gl->vertex_buffer_obj_available) {\n        fprintf(stdout, \"[GL] Error: GL_ARB_vertex_buffer_object is not available!\\n\");\n        failed = nk_true;\n    }\n    if (!gl->fragment_program_available) {\n        fprintf(stdout, \"[GL] Error: GL_ARB_fragment_program is not available!\\n\");\n        failed = nk_true;\n    }\n    if (!gl->vertex_array_obj_available) {\n        fprintf(stdout, \"[GL] Error: GL_ARB_vertex_array_object is not available!\\n\");\n        failed = nk_true;\n    }\n    if (!gl->frame_buffer_object_available) {\n        fprintf(stdout, \"[GL] Error: GL_ARB_framebuffer_object is not available!\\n\");\n        failed = nk_true;\n    }\n    return !failed;\n}\n#endif\n\nNK_API int\nnk_x11_device_create(void)\n{\n    GLint status;\n    static const GLchar *vertex_shader =\n        NK_SHADER_VERSION\n        \"uniform mat4 ProjMtx;\\n\"\n        \"in vec2 Position;\\n\"\n        \"in vec2 TexCoord;\\n\"\n        \"in vec4 Color;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main() {\\n\"\n        \"   Frag_UV = TexCoord;\\n\"\n        \"   Frag_Color = Color;\\n\"\n        \"   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\\n\"\n        \"}\\n\";\n    static const GLchar *fragment_shader =\n        NK_SHADER_VERSION\n        \"precision mediump float;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"out vec4 Out_Color;\\n\"\n        \"void main(){\\n\"\n        \"   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    struct nk_x11_device *dev = &x11.ogl;\n#ifdef NK_XLIB_LOAD_OPENGL_EXTENSIONS\n    if (!nk_load_opengl(&dev->info)) return 0;\n#endif\n    nk_buffer_init_default(&dev->cmds);\n\n    dev->prog = glCreateProgram();\n    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);\n    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);\n    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);\n    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);\n    glCompileShader(dev->vert_shdr);\n    glCompileShader(dev->frag_shdr);\n    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glAttachShader(dev->prog, dev->vert_shdr);\n    glAttachShader(dev->prog, dev->frag_shdr);\n    glLinkProgram(dev->prog);\n    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);\n    assert(status == GL_TRUE);\n\n    dev->uniform_tex = glGetUniformLocation(dev->prog, \"Texture\");\n    dev->uniform_proj = glGetUniformLocation(dev->prog, \"ProjMtx\");\n    dev->attrib_pos = glGetAttribLocation(dev->prog, \"Position\");\n    dev->attrib_uv = glGetAttribLocation(dev->prog, \"TexCoord\");\n    dev->attrib_col = glGetAttribLocation(dev->prog, \"Color\");\n\n    {\n        /* buffer setup */\n        GLsizei vs = sizeof(struct nk_x11_vertex);\n        size_t vp = offsetof(struct nk_x11_vertex, position);\n        size_t vt = offsetof(struct nk_x11_vertex, uv);\n        size_t vc = offsetof(struct nk_x11_vertex, col);\n\n        glGenBuffers(1, &dev->vbo);\n        glGenBuffers(1, &dev->ebo);\n        glGenVertexArrays(1, &dev->vao);\n\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glEnableVertexAttribArray((GLuint)dev->attrib_pos);\n        glEnableVertexAttribArray((GLuint)dev->attrib_uv);\n        glEnableVertexAttribArray((GLuint)dev->attrib_col);\n\n        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);\n        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);\n        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);\n    }\n\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n    return 1;\n}\n\nNK_INTERN void\nnk_x11_device_upload_atlas(const void *image, int width, int height)\n{\n    struct nk_x11_device *dev = &x11.ogl;\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nNK_API void\nnk_x11_device_destroy(void)\n{\n    struct nk_x11_device *dev = &x11.ogl;\n    glDetachShader(dev->prog, dev->vert_shdr);\n    glDetachShader(dev->prog, dev->frag_shdr);\n    glDeleteShader(dev->vert_shdr);\n    glDeleteShader(dev->frag_shdr);\n    glDeleteProgram(dev->prog);\n    glDeleteTextures(1, &dev->font_tex);\n    glDeleteBuffers(1, &dev->vbo);\n    glDeleteBuffers(1, &dev->ebo);\n    nk_buffer_free(&dev->cmds);\n}\n\nNK_API void\nnk_x11_render(enum nk_anti_aliasing AA, int max_vertex_buffer, int max_element_buffer)\n{\n    int width, height;\n    XWindowAttributes attr;\n    struct nk_x11_device *dev = &x11.ogl;\n    GLfloat ortho[4][4] = {\n        {  2.0f,  0.0f,  0.0f, 0.0f },\n        {  0.0f, -2.0f,  0.0f, 0.0f },\n        {  0.0f,  0.0f, -1.0f, 0.0f },\n        { -1.0f,  1.0f,  0.0f, 1.0f },\n    };\n    double now = nk_get_time();\n    x11.ctx.delta_time_seconds = now - x11.time_of_last_frame;\n    x11.time_of_last_frame = now;\n\n    XGetWindowAttributes(x11.dpy, x11.win, &attr);\n    width = attr.width;\n    height = attr.height;\n\n    ortho[0][0] /= (GLfloat)width;\n    ortho[1][1] /= (GLfloat)height;\n\n    /* setup global state */\n    glEnable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glActiveTexture(GL_TEXTURE0);\n\n    /* setup program */\n    glUseProgram(dev->prog);\n    glUniform1i(dev->uniform_tex, 0);\n    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);\n    glViewport(0,0,(GLsizei)width,(GLsizei)height);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        void *vertices, *elements;\n        const nk_draw_index *offset = NULL;\n        struct nk_buffer vbuf, ebuf;\n\n        /* allocate vertex and element buffer */\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glBufferData(GL_ARRAY_BUFFER, max_vertex_buffer, NULL, GL_STREAM_DRAW);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, max_element_buffer, NULL, GL_STREAM_DRAW);\n\n        /* load draw vertices & elements directly into vertex + element buffer */\n        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);\n        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n                {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, position)},\n                {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_x11_vertex, uv)},\n                {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_x11_vertex, col)},\n                {NK_VERTEX_LAYOUT_END}\n            };\n            memset(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_x11_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_x11_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            nk_buffer_init_fixed(&vbuf, vertices, (size_t)max_vertex_buffer);\n            nk_buffer_init_fixed(&ebuf, elements, (size_t)max_element_buffer);\n            nk_convert(&x11.ctx, &dev->cmds, &vbuf, &ebuf, &config);\n        }\n        glUnmapBuffer(GL_ARRAY_BUFFER);\n        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);\n\n        /* iterate over and execute each draw command */\n        nk_draw_foreach(cmd, &x11.ctx, &dev->cmds)\n        {\n            if (!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor(\n                (GLint)(cmd->clip_rect.x),\n                (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),\n                (GLint)(cmd->clip_rect.w),\n                (GLint)(cmd->clip_rect.h));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(&x11.ctx);\n        nk_buffer_clear(&dev->cmds);\n    }\n\n    /* default OpenGL state */\n    glUseProgram(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n    glDisable(GL_BLEND);\n    glDisable(GL_SCISSOR_TEST);\n}\n\nNK_API void\nnk_x11_font_stash_begin(struct nk_font_atlas **atlas)\n{\n    nk_font_atlas_init_default(&x11.atlas);\n    nk_font_atlas_begin(&x11.atlas);\n    *atlas = &x11.atlas;\n}\n\nNK_API void\nnk_x11_font_stash_end(void)\n{\n    const void *image; int w, h;\n    image = nk_font_atlas_bake(&x11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    nk_x11_device_upload_atlas(image, w, h);\n    nk_font_atlas_end(&x11.atlas, nk_handle_id((int)x11.ogl.font_tex), &x11.ogl.tex_null);\n    if (x11.atlas.default_font)\n        nk_style_set_font(&x11.ctx, &x11.atlas.default_font->handle);\n}\n\nNK_API int\nnk_x11_handle_event(XEvent *evt)\n{\n    struct nk_context *ctx = &x11.ctx;\n    static int insert_toggle = 0;\n\n    /* optional grabbing behavior */\n    if (ctx->input.mouse.grab) {\n        XDefineCursor(x11.dpy, x11.win, x11.cursor);\n        ctx->input.mouse.grab = 0;\n    } else if (ctx->input.mouse.ungrab) {\n        XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0,\n            (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);\n        XUndefineCursor(x11.dpy, x11.win);\n        ctx->input.mouse.ungrab = 0;\n    }\n\n    if (evt->type == KeyPress || evt->type == KeyRelease)\n    {\n        /* Key handler */\n        int ret, down = (evt->type == KeyPress);\n        KeySym *code = XGetKeyboardMapping(x11.dpy, (KeyCode)evt->xkey.keycode, 1, &ret);\n        if (*code == XK_Shift_L || *code == XK_Shift_R) nk_input_key(ctx, NK_KEY_SHIFT, down);\n        else if (*code == XK_Control_L || *code == XK_Control_R) nk_input_key(ctx, NK_KEY_CTRL, down);\n        else if (*code == XK_Delete)    nk_input_key(ctx, NK_KEY_DEL, down);\n        else if (*code == XK_Return || *code == XK_KP_Enter)    nk_input_key(ctx, NK_KEY_ENTER, down);\n        else if (*code == XK_Tab)       nk_input_key(ctx, NK_KEY_TAB, down);\n        else if (*code == XK_Left)      nk_input_key(ctx, NK_KEY_LEFT, down);\n        else if (*code == XK_Right)     nk_input_key(ctx, NK_KEY_RIGHT, down);\n        else if (*code == XK_Up)        nk_input_key(ctx, NK_KEY_UP, down);\n        else if (*code == XK_Down)      nk_input_key(ctx, NK_KEY_DOWN, down);\n        else if (*code == XK_BackSpace) nk_input_key(ctx, NK_KEY_BACKSPACE, down);\n        else if (*code == XK_Escape)    nk_input_key(ctx, NK_KEY_TEXT_RESET_MODE, down);\n        else if (*code == XK_Page_Up)   nk_input_key(ctx, NK_KEY_SCROLL_UP, down);\n        else if (*code == XK_Page_Down) nk_input_key(ctx, NK_KEY_SCROLL_DOWN, down);\n        else if (*code == XK_Home) {\n            nk_input_key(ctx, NK_KEY_TEXT_START, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_START, down);\n        } else if (*code == XK_End) {\n            nk_input_key(ctx, NK_KEY_TEXT_END, down);\n            nk_input_key(ctx, NK_KEY_SCROLL_END, down);\n        } else {\n            if (*code == 'c' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_COPY, down);\n            else if (*code == 'v' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_PASTE, down);\n            else if (*code == 'x' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_CUT, down);\n            else if (*code == 'z' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_UNDO, down);\n            else if (*code == 'r' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_REDO, down);\n            else if (*code == XK_Left && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_LEFT, down);\n            else if (*code == XK_Right && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_WORD_RIGHT, down);\n            else if (*code == 'b' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_LINE_START, down);\n            else if (*code == 'e' && (evt->xkey.state & ControlMask))\n                nk_input_key(ctx, NK_KEY_TEXT_LINE_END, down);\n            else if (*code == XK_Insert) {\n                if (down) insert_toggle = !insert_toggle;\n                if (insert_toggle) {\n                    nk_input_key(ctx, NK_KEY_TEXT_INSERT_MODE, down);\n                } else {\n                    nk_input_key(ctx, NK_KEY_TEXT_REPLACE_MODE, down);\n                }\n            } else {\n                if (down) {\n                    char buf[32];\n                    KeySym keysym = 0;\n                    if (XLookupString((XKeyEvent*)evt, buf, 32, &keysym, NULL) != NoSymbol)\n                        nk_input_glyph(ctx, buf);\n                }\n            }\n        }\n        XFree(code);\n        return 1;\n    } else if (evt->type == ButtonPress || evt->type == ButtonRelease) {\n        /* Button handler */\n        int down = (evt->type == ButtonPress);\n        const int x = evt->xbutton.x, y = evt->xbutton.y;\n        if (evt->xbutton.button == Button1) {\n            if (down) { /* Double-Click Button handler */\n                float dt = nk_get_time() - x11.last_button_click;\n                if (dt > NK_X11_DOUBLE_CLICK_LO && dt < NK_X11_DOUBLE_CLICK_HI)\n                    nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_true);\n                x11.last_button_click = nk_get_time();\n            } else nk_input_button(ctx, NK_BUTTON_DOUBLE, x, y, nk_false);\n            nk_input_button(ctx, NK_BUTTON_LEFT, x, y, down);\n        } else if (evt->xbutton.button == Button2)\n            nk_input_button(ctx, NK_BUTTON_MIDDLE, x, y, down);\n        else if (evt->xbutton.button == Button3)\n            nk_input_button(ctx, NK_BUTTON_RIGHT, x, y, down);\n        else if (evt->xbutton.button == Button4)\n            nk_input_scroll(ctx, nk_vec2(0,1.0f));\n        else if (evt->xbutton.button == Button5)\n            nk_input_scroll(ctx, nk_vec2(0,-1.0f));\n        else if (evt->xbutton.button == 8)\n            nk_input_button(ctx, NK_BUTTON_X1, x, y, down);\n        else if (evt->xbutton.button == 9)\n            nk_input_button(ctx, NK_BUTTON_X2, x, y, down);\n        else return 0;\n        return 1;\n    } else if (evt->type == MotionNotify) {\n        /* Mouse motion handler */\n        const int x = evt->xmotion.x, y = evt->xmotion.y;\n        nk_input_motion(ctx, x, y);\n        if (ctx->input.mouse.grabbed) {\n            ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;\n            ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;\n            XWarpPointer(x11.dpy, None, x11.win, 0, 0, 0, 0, (int)ctx->input.mouse.pos.x, (int)ctx->input.mouse.pos.y);\n        }\n        return 1;\n    } else if (evt->type == KeymapNotify) {\n        XRefreshKeyboardMapping(&evt->xmapping);\n        return 1;\n    }\n    return 0;\n}\n\nNK_API struct nk_context*\nnk_x11_init(Display *dpy, Window win)\n{\n    if (!setlocale(LC_ALL,\"\")) return 0;\n    if (!XSupportsLocale()) return 0;\n    if (!XSetLocaleModifiers(\"@im=none\")) return 0;\n    if (!nk_x11_device_create()) return 0;\n\n    x11.dpy = dpy;\n    x11.win = win;\n\n    /* create invisible cursor */\n    {static XColor dummy; char data[1] = {0};\n    Pixmap blank = XCreateBitmapFromData(dpy, win, data, 1, 1);\n    if (blank == None) return 0;\n    x11.cursor = XCreatePixmapCursor(dpy, blank, blank, &dummy, &dummy, 0, 0);\n    XFreePixmap(dpy, blank);}\n\n    nk_init_default(&x11.ctx, 0);\n    x11.time_of_last_frame = nk_get_time();\n    return &x11.ctx;\n}\n\nNK_API void\nnk_x11_shutdown(void)\n{\n    nk_font_atlas_clear(&x11.atlas);\n    nk_free(&x11.ctx);\n    nk_x11_device_destroy();\n    XFreeCursor(x11.dpy, x11.cursor);\n    memset(&x11, 0, sizeof(x11));\n}\n\n#endif\n"
  },
  {
    "path": "demo/xcb_cairo/Makefile",
    "content": "# Target\nBIN = demo\nCFLAGS += -std=c89 -pedantic\nLDFLAGS += -lm\nSRC = ${wildcard *.c}\nOBJ = $(SRC:.c=.o)\n\n# Freetype\nCFLAGS += ${shell pkg-config --cflags freetype2}\nLDFLAGS += ${shell pkg-config --libs freetype2}\n\n# XCB\nCFLAGS += ${shell pkg-config --cflags xcb xcb-util xcb-keysyms xkbcommon xkbcommon-x11}\nLDFLAGS += ${shell pkg-config --libs xcb xcb-util xcb-keysyms xkbcommon xkbcommon-x11}\n\n# Cairo\nCFLAGS += ${shell pkg-config --cflags cairo}\nLDFLAGS += ${shell pkg-config --libs cairo}\n\n# Rules\n$(BIN):\n\t@mkdir -p bin\n\trm -f bin/$(BIN) $(OBJS)\n\t$(CC) $(SRC) $(CFLAGS) -D_POSIX_C_SOURCE=200809L -o bin/$(BIN) ${LDFLAGS}\n"
  },
  {
    "path": "demo/xcb_cairo/main.c",
    "content": "/* nuklear - v1.32.0 - public domain */\n#include <assert.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdarg.h>\n#include <string.h>\n#include <limits.h>\n#include <math.h>\n#include <sys/time.h>\n#include <unistd.h>\n#include <time.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_STANDARD_VARARGS\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_IMPLEMENTATION\n#include \"../../nuklear.h\"\n\n#define NK_XCB_CAIRO_IMPLEMENTATION\n#include \"nuklear_xcb.h\"\n\nstatic void die(const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    fputs(\"\\n\", stderr);\n    exit(EXIT_FAILURE);\n}\n\n/* ===============================================================\n *\n *                          EXAMPLE\n *\n * ===============================================================*/\n/* This are some code examples to provide a small overview of what can be\n * done with this library. To try out an example uncomment the defines */\n\n/*#define INCLUDE_ALL */\n/*#define INCLUDE_STYLE */\n/*#define INCLUDE_CALCULATOR */\n#define INCLUDE_OVERVIEW\n/*#define INCLUDE_CONFIGURATOR */\n/*#define INCLUDE_NODE_EDITOR */\n/*#define INCLUDE_CANVAS */\n\n#ifdef INCLUDE_ALL\n  #define INCLUDE_STYLE\n  #define INCLUDE_CALCULATOR\n  #define INCLUDE_OVERVIEW\n  #define INCLUDE_NODE_EDITOR\n  #define INCLUDE_CONFIGURATOR\n  #define INCLUDE_CANVAS\n#endif\n\n#ifdef INCLUDE_STYLE\n  #include \"../common/style.c\"\n#endif\n#ifdef INCLUDE_CALCULATOR\n  #include \"../common/calculator.c\"\n#endif\n#ifdef INCLUDE_OVERVIEW\n  #include \"../common/overview.c\"\n#endif\n#ifdef INCLUDE_CONFIGURATOR\n  #include \"../../demo/common/style_configurator.c\"\n#endif\n#ifdef INCLUDE_NODE_EDITOR\n  #include \"../common/node_editor.c\"\n#endif\n#ifdef INCLUDE_CANVAS\n  #include \"../common/canvas.c\"\n#endif\n\n/* ===============================================================\n *\n *                          DEMO\n *\n * ===============================================================*/\nint\nmain(void)\n{\n    struct nk_xcb_context *xcb_ctx;\n    struct nk_color background = nk_rgb(0, 0, 0);\n    struct nk_cairo_context *cairo_ctx;\n    struct nk_user_font *font;\n    struct nk_context* ctx;\n    int running = 1;\n    int events;\n\n    #ifdef INCLUDE_CONFIGURATOR\n    static struct nk_color color_table[NK_COLOR_COUNT];\n    memcpy(color_table, nk_default_color_style, sizeof(color_table));\n    #endif\n\n    xcb_ctx = nk_xcb_init(\"Nuklear XCB/Cairo\", 20, 20, 600, 800);\n    cairo_ctx = nk_cairo_init(&background, NULL, 0, nk_xcb_create_cairo_surface(xcb_ctx));\n    /*cairo_ctx = nk_cairo_init(&background, \"../../extra_font/DroidSans.ttf\", 0, nk_xcb_create_surface(xcb_ctx));*/\n    font = nk_cairo_default_font(cairo_ctx);\n    ctx = malloc(sizeof(struct nk_context));\n    nk_init_default(ctx, font);\n\n    #ifdef INCLUDE_STYLE\n    set_style(ctx, THEME_BLACK);\n    /*nk_style_push_float(ctx, &ctx->style.window.rounding, 20.0f);*/\n    /*set_style(ctx, THEME_WHITE);*/\n    /*set_style(ctx, THEME_RED);*/\n    /*set_style(ctx, THEME_BLUE);*/\n    /*set_style(ctx, THEME_DARK);*/\n    #endif\n\n    while (running)\n    {\n        /* Events */\n        events = nk_xcb_handle_event(xcb_ctx, ctx);\n        if (events & NK_XCB_EVENT_STOP) {\n            break;\n        }\n        if (events & NK_XCB_EVENT_PAINT) {\n            nk_cairo_damage(cairo_ctx);\n        }\n        if (events & NK_XCB_EVENT_RESIZED) {\n            nk_xcb_resize_cairo_surface(xcb_ctx, nk_cairo_surface(cairo_ctx));\n        }\n\n        /* GUI */\n        if (nk_begin(ctx, \"Demo\", nk_rect(50, 50, 200, 200),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|\n            NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))\n        {\n            enum {EASY, HARD};\n            static int op = EASY;\n            static int property = 20;\n\n            nk_layout_row_static(ctx, 30, 80, 1);\n            if (nk_button_label(ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n            nk_layout_row_dynamic(ctx, 30, 2);\n            if (nk_option_label(ctx, \"easy\", op == EASY)) op = EASY;\n            if (nk_option_label(ctx, \"hard\", op == HARD)) op = HARD;\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_property_int(ctx, \"Compression:\", 0, &property, 100, 10, 1);\n        }\n        nk_end(ctx);\n        if (nk_window_is_hidden(ctx, \"Demo\")) {\n            break;\n        }\n\n        /* -------------- EXAMPLES ---------------- */\n        #ifdef INCLUDE_CALCULATOR\n        calculator(ctx);\n        #endif\n        #ifdef INCLUDE_OVERVIEW\n        overview(ctx);\n        #endif\n        #ifdef INCLUDE_CONFIGURATOR\n          style_configurator(ctx, color_table);\n        #endif\n        #ifdef INCLUDE_NODE_EDITOR\n        node_editor(ctx);\n        #endif\n        #ifdef INCLUDE_CANVAS\n        canvas(ctx);\n        #endif\n        /* ----------------------------------------- */\n\n        /* Render */\n        nk_cairo_render(cairo_ctx, ctx);\n        nk_xcb_render(xcb_ctx);\n        nk_clear(ctx);\n    }\n\n    nk_free(ctx);\n    free(ctx);\n    nk_cairo_free(cairo_ctx);\n    nk_xcb_free(xcb_ctx);\n\n    return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "demo/xcb_cairo/nuklear_xcb.h",
    "content": "/*****************************************************************************\n *\n * Nuklear XCB/Cairo Render Backend - v0.0.2\n * Copyright 2021 Richard Gill\n *\n * Grabbed and adapted from https://github.com/griebd/nuklear_xcb\n * Copyright 2017 Adriano Grieb\n *\n * Permission is hereby granted, free of charge, to any person obtaining a\n * copy of this software and associated documentation files (the \"Software\"),\n * to deal in the Software without restriction, including without limitation\n * the rights to use, copy, modify, merge, publish, distribute, sublicense,\n * and/or sell copies of the Software, and to permit persons to whom the\n * Software is furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\n * DEALINGS IN THE SOFTWARE.\n *\n ****************************************************************************/\n\n/*****************************************************************************\n *\n *                                API\n *\n ****************************************************************************/\n\n#ifndef NK_XCB_CAIRO_H\n#define NK_XCB_CAIRO_H\n\nstruct nk_xcb_context;\nstruct nk_cairo_context;\n\n/* With Xcb, we work mostly on events, so to do something only when\n * needed it's good to know what kind of events pulled us from sleep\n */\nenum nk_xcb_event_type {\n    NK_XCB_EVENT_PAINT      = 0x02,\n    NK_XCB_EVENT_RESIZED    = 0x04,\n    NK_XCB_EVENT_STOP       = 0x08,\n    NK_XCB_CLIENT_MESSAGE   = 0x10\n};\n\n/* Xcb part: work on windows */\nNK_API struct nk_xcb_context *nk_xcb_init(const char *title, int pos_x, int pos_y, int width, int height);\nNK_API void nk_xcb_free(struct nk_xcb_context *xcb_ctx);\n\nNK_API int nk_xcb_handle_event(struct nk_xcb_context *xcb_ctx, struct nk_context *nk_ctx);\nNK_API void nk_xcb_render(struct nk_xcb_context *xcb_ctx);\nNK_API void nk_xcb_size(struct nk_xcb_context *xcb_ctx, int *width, int *height);\n\n/* TODO: copy/paste */\n\n/* Cairo part: work on painting */\nNK_API struct nk_cairo_context *nk_cairo_init(struct nk_color *bg, const char *font_file, double font_size, void *surface);\nNK_API void nk_cairo_free(struct nk_cairo_context *cairo_ctx);\n\nNK_API struct nk_user_font *nk_cairo_default_font(struct nk_cairo_context *cairo_ctx);\nNK_API void nk_cairo_damage(struct nk_cairo_context *cairo_ctx);\nNK_API int nk_cairo_render(struct nk_cairo_context *cairo_ctx, struct nk_context *ctx);\n\n/* Bridge between xcb and cairo (so it's possible to use them like legos) */\nNK_API void *nk_xcb_create_cairo_surface(struct nk_xcb_context *xcb_ctx);\nNK_API void nk_xcb_resize_cairo_surface(struct nk_xcb_context *xcb_ctx, void *surface);\n\n\n#endif /* NK_XCB_CAIRO_H */\n\n/*****************************************************************************\n *\n *                           IMPLEMENTATION\n *\n ****************************************************************************/\n\n#ifdef NK_XCB_CAIRO_IMPLEMENTATION\n\n#include <xcb/xcb.h>\n#include <xcb/xcb_util.h>\n#include <xcb/xcb_keysyms.h>\n#include <X11/keysym.h>\n#include <cairo/cairo-xcb.h>\n#include <cairo/cairo-ft.h>\n\n#include <xkbcommon/xkbcommon.h>\n#include <xkbcommon/xkbcommon-x11.h>\n\n\n#if defined _XOPEN_SOURCE && _XOPEN_SOURCE >= 600 || \\\n    defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 200112L\n#include <time.h>\n#include <errno.h>\n#ifndef NK_XCB_FPS\n#define NK_XCB_FPS 30\n#endif /* NK_XCB_FPS */\n#define NK_XCB_NSEC 1000000000\n#define NK_XCB_MIN_FRAME_TIME (NK_XCB_NSEC / NK_XCB_FPS)\n#endif\n\n#include <math.h>\n#ifdef __USE_GNU\n#define NK_XCB_PI M_PIl\n#elif defined __USE_BSD || defined __USE_XOPEN\n#define NK_XCB_PI M_PI\n#else\n#define NK_XCB_PI acos(-1.0)\n#endif\n\n#define NK_XCB_TO_CAIRO(x) ((double) x / 255.0)\n#define NK_XCB_DEG_TO_RAD(x) ((double) x * NK_XCB_PI / 180.0)\n\ntypedef struct xkb_context xkb_context;\ntypedef struct xkb_keymap xkb_keymap;\ntypedef struct xkb_state xkb_state;\ntypedef struct xkbcommon_context xkbcommon_context;\ntypedef struct nk_xcb_context nk_xcb_context;\n\nstruct xkbcommon_context\n{\n\tstruct xkb_context *ctx;\n\tstruct xkb_keymap *keymap;\n\tstruct xkb_state *state;\n};\n\nNK_INTERN void xkbcommon_free(xkbcommon_context *kbdctx);\nNK_INTERN xkbcommon_context *xkbcommon_init(xcb_connection_t *conn);\nNK_INTERN xkb_keysym_t keycode_to_keysym(nk_xcb_context *ctx, xkb_keycode_t keycode, int pressed);\n\nstruct nk_cairo_context {\n    cairo_surface_t *surface;\n    cairo_t *cr;\n\n    struct nk_user_font *font;\n    struct nk_color *bg;\n\n    void *last_buffer;\n    nk_size buffer_size;\n    int repaint;\n};\n\nstruct nk_xcb_context {\n    xcb_connection_t *conn;\n    int screennum;\n    xcb_window_t window;\n    /* xcb_key_symbols_t *key_symbols; */\n    xkbcommon_context *xkbcommon_ctx;\n#ifdef NK_XCB_MIN_FRAME_TIME\n    unsigned long last_render;\n#endif /* NK_XCB_MIN_FRAME_TIME */\n    int events;\n    xcb_intern_atom_reply_t* del_atom;\n    int width, height;\n    xcb_client_message_event_t last_client_message;\n};\n\nNK_API struct nk_xcb_context *nk_xcb_init(const char *title, int pos_x, int pos_y, int width, int height)\n{\n    int screenNum;\n    xcb_connection_t *conn;\n    xcb_screen_t *screen;\n    xcb_window_t window;\n    uint32_t values[1];\n    struct nk_xcb_context *xcb_ctx;\n    xcb_intern_atom_cookie_t cookie;\n    xcb_intern_atom_reply_t *reply, *del_atom;\n\n    conn = xcb_connect(NULL, &screenNum);\n    if (xcb_connection_has_error(conn)) {\n        xcb_disconnect(conn);\n        return NULL;\n    }\n    screen = xcb_aux_get_screen(conn, screenNum);\n\n    window = xcb_generate_id(conn);\n    values[0] = XCB_EVENT_MASK_KEY_PRESS\n        | XCB_EVENT_MASK_KEY_RELEASE\n        | XCB_EVENT_MASK_BUTTON_PRESS\n        | XCB_EVENT_MASK_BUTTON_RELEASE\n        | XCB_EVENT_MASK_POINTER_MOTION\n        | XCB_EVENT_MASK_BUTTON_1_MOTION\n        | XCB_EVENT_MASK_BUTTON_2_MOTION\n        | XCB_EVENT_MASK_BUTTON_3_MOTION\n        | XCB_EVENT_MASK_BUTTON_4_MOTION\n        | XCB_EVENT_MASK_BUTTON_5_MOTION\n        | XCB_EVENT_MASK_BUTTON_MOTION\n        | XCB_EVENT_MASK_KEYMAP_STATE\n        | XCB_EVENT_MASK_EXPOSURE\n        | XCB_EVENT_MASK_STRUCTURE_NOTIFY\n        ;\n    xcb_create_window(conn, XCB_COPY_FROM_PARENT, window, screen->root,\n            pos_x, pos_y, width, height, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT,\n            XCB_COPY_FROM_PARENT, XCB_CW_EVENT_MASK, values);\n\n\txcb_change_property(conn,\n\t\tXCB_PROP_MODE_REPLACE,\n\t\twindow,\n\t\tXCB_ATOM_WM_NAME,\n\t\tXCB_ATOM_STRING,\n\t\t8,\n\t\tstrlen(title),\n\t\ttitle);\n\n    cookie = xcb_intern_atom(conn, 1, 12, \"WM_PROTOCOLS\");\n    reply = xcb_intern_atom_reply(conn, cookie, 0);\n    cookie = xcb_intern_atom(conn, 0, 16, \"WM_DELETE_WINDOW\");\n    del_atom = xcb_intern_atom_reply(conn, cookie, 0);\n    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, window, reply->atom, 4, 32, 1, &del_atom->atom);\n    free(reply);\n\n    xcb_map_window(conn, window);\n    xcb_flush(conn);\n\n    xcb_ctx = (struct nk_xcb_context *)malloc(sizeof (struct nk_xcb_context));\n    xcb_ctx->conn = conn;\n    xcb_ctx->screennum = screenNum;\n    xcb_ctx->window = window;\n    /* xcb_ctx->key_symbols = xcb_key_symbols_alloc(xcb_ctx->conn); */\n    xcb_ctx->xkbcommon_ctx = xkbcommon_init(conn);\n    xcb_ctx->del_atom = del_atom;\n    xcb_ctx->width = width;\n    xcb_ctx->height = height;\n\n    return xcb_ctx;\n}\n\nNK_API void nk_xcb_free(struct nk_xcb_context *xcb_ctx)\n{\n\txkbcommon_free(xcb_ctx->xkbcommon_ctx);\n    free(xcb_ctx->del_atom);\n    /* xcb_key_symbols_free(xcb_ctx->key_symbols); */\n    xcb_disconnect(xcb_ctx->conn);\n    free(xcb_ctx);\n}\n\nNK_API int nk_xcb_handle_event(struct nk_xcb_context *xcb_ctx, struct nk_context *nk_ctx)\n{\n    int events = 0;\n    xcb_generic_event_t *event;\n    static int insert_toggle = 0;\n    static const xcb_client_message_event_t EMPTY_CLIENT_MESSAGE;\n\n#ifdef NK_XCB_MIN_FRAME_TIME\n    struct timespec tp;\n\n    clock_gettime(CLOCK_MONOTONIC_COARSE, &tp);\n    xcb_ctx->last_render = tp.tv_sec * NK_XCB_NSEC + tp.tv_nsec;\n#endif /* NK_XCB_MIN_FRAME_TIME */\n\n    event = xcb_wait_for_event(xcb_ctx->conn);\n\n    xcb_ctx->last_client_message = EMPTY_CLIENT_MESSAGE;\n    nk_input_begin(nk_ctx);\n    do {\n        switch (XCB_EVENT_RESPONSE_TYPE(event)) {\n        case XCB_KEY_PRESS:\n        case XCB_KEY_RELEASE:\n            {\n                int press = (XCB_EVENT_RESPONSE_TYPE(event)) == XCB_KEY_PRESS;\n                xcb_key_press_event_t *kp = (xcb_key_press_event_t *)event;\n                /* xcb_keysym_t sym = xcb_key_symbols_get_keysym(xcb_ctx->key_symbols, kp->detail, kp->state);*/\n                xcb_keysym_t sym = keycode_to_keysym(xcb_ctx, kp->detail, press);\n\n                switch (sym) {\n                case XK_Shift_L:\n                case XK_Shift_R:\n                    nk_input_key(nk_ctx, NK_KEY_SHIFT, press);\n                    break;\n                case XK_Control_L:\n                case XK_Control_R:\n                    nk_input_key(nk_ctx, NK_KEY_CTRL, press);\n                    break;\n                case XK_Delete:\n                    nk_input_key(nk_ctx, NK_KEY_DEL, press);\n                    break;\n                case XK_Return:\n                case XK_KP_Enter:\n                    nk_input_key(nk_ctx, NK_KEY_ENTER, press);\n                    break;\n                case XK_Tab:\n                    nk_input_key(nk_ctx, NK_KEY_TAB, press);\n                    break;\n                case XK_BackSpace:\n                    nk_input_key(nk_ctx, NK_KEY_BACKSPACE, press);\n                    break;\n                /* case NK_KEY_COPY */\n                /* case NK_KEY_CUT */\n                /* case NK_KEY_PASTE */\n                case XK_Up:\n                    nk_input_key(nk_ctx, NK_KEY_UP, press);\n                    break;\n                case XK_Down:\n                    nk_input_key(nk_ctx, NK_KEY_DOWN, press);\n                    break;\n                case XK_Left:\n                    nk_input_key(nk_ctx, NK_KEY_LEFT, press);\n                    break;\n                case XK_Right:\n                    nk_input_key(nk_ctx, NK_KEY_RIGHT, press);\n                    break;\n                case XK_Insert:\n                    if (press) insert_toggle = !insert_toggle;\n                    if (insert_toggle) {\n                        nk_input_key(nk_ctx, NK_KEY_TEXT_INSERT_MODE, press);\n                    } else {\n                        nk_input_key(nk_ctx, NK_KEY_TEXT_REPLACE_MODE, press);\n                    }\n                    break;\n                case XK_Escape:\n                    nk_input_key(nk_ctx, NK_KEY_TEXT_RESET_MODE, press);\n                    break;\n                /* NK_KEY_TEXT_LINE_START, */\n                /* NK_KEY_TEXT_LINE_END, */\n                case XK_Home:\n                    {\n                        nk_input_key(nk_ctx, NK_KEY_TEXT_START, press);\n                        nk_input_key(nk_ctx, NK_KEY_SCROLL_START, press);\n                    }\n                    break;\n                case XK_End:\n                    {\n                        nk_input_key(nk_ctx, NK_KEY_TEXT_END, press);\n                        nk_input_key(nk_ctx, NK_KEY_SCROLL_END, press);\n                    }\n                    break;\n                /* NK_KEY_TEXT_UNDO, */\n                /* NK_KEY_TEXT_REDO, */\n                /* NK_KEY_TEXT_SELECT_ALL, */\n                /* NK_KEY_TEXT_WORD_LEFT, */\n                /* NK_KEY_TEXT_WORD_RIGHT, */\n                case XK_Page_Down:\n                    nk_input_key(nk_ctx, NK_KEY_SCROLL_DOWN, press);\n                    break;\n                case XK_Page_Up:\n                    nk_input_key(nk_ctx, NK_KEY_SCROLL_UP, press);\n                    break;\n                default:\n                    if (press &&\n                            !xcb_is_keypad_key(sym) &&\n                            !xcb_is_private_keypad_key(sym) &&\n                            !xcb_is_cursor_key(sym) &&\n                            !xcb_is_pf_key(sym) &&\n                            !xcb_is_function_key(sym) &&\n                            !xcb_is_misc_function_key(sym) &&\n                            !xcb_is_modifier_key(sym)\n                            ) {\n                        /* nk_input_char(nk_ctx, sym); */\n                        nk_input_unicode(nk_ctx, sym);\n                    }\n                    else {\n                        printf(\"state: %x code: %x sum: %x\\n\", kp->state, kp->detail, sym);\n                    }\n                    break;\n                }\n            }\n            break;\n        case XCB_BUTTON_PRESS:\n        case XCB_BUTTON_RELEASE:\n            {\n                int press = (XCB_EVENT_RESPONSE_TYPE(event)) == XCB_BUTTON_PRESS;\n                xcb_button_press_event_t *bp = (xcb_button_press_event_t *)event;\n                switch (bp->detail) {\n                case XCB_BUTTON_INDEX_1:\n                    nk_input_button(nk_ctx, NK_BUTTON_LEFT, bp->event_x, bp->event_y, press);\n                    break;\n                case XCB_BUTTON_INDEX_2:\n                    nk_input_button(nk_ctx, NK_BUTTON_MIDDLE, bp->event_x, bp->event_y, press);\n                    break;\n                case XCB_BUTTON_INDEX_3:\n                    nk_input_button(nk_ctx, NK_BUTTON_RIGHT, bp->event_x, bp->event_y, press);\n                    break;\n                case XCB_BUTTON_INDEX_4:\n                    nk_input_scroll(nk_ctx, nk_vec2(0, 1.0f));\n                    break;\n                case XCB_BUTTON_INDEX_5:\n                    nk_input_scroll(nk_ctx, nk_vec2(0, -1.0f));\n                    break;\n                case 8:\n                    nk_input_button(nk_ctx, NK_BUTTON_X1, bp->event_x, bp->event_y, press);\n                    break;\n                case 9:\n                    nk_input_button(nk_ctx, NK_BUTTON_X2, bp->event_x, bp->event_y, press);\n                    break;\n                default: break;\n                }\n            }\n            break;\n        case XCB_MOTION_NOTIFY:\n            {\n                xcb_motion_notify_event_t *mn = (xcb_motion_notify_event_t *)event;\n                nk_input_motion(nk_ctx, mn->event_x, mn->event_y);\n            }\n            break;\n        case XCB_SELECTION_CLEAR:\n            {\n                printf(\"Unhandled event: %s\\n\", xcb_event_get_label(event->response_type));\n            }\n            break;\n        case XCB_SELECTION_REQUEST:\n            {\n                printf(\"Unhandled event: %s\\n\", xcb_event_get_label(event->response_type));\n            }\n            break;\n        case XCB_SELECTION_NOTIFY:\n            {\n                printf(\"Unhandled event: %s\\n\", xcb_event_get_label(event->response_type));\n            }\n            break;\n        case XCB_CONFIGURE_NOTIFY:\n            {\n                xcb_configure_notify_event_t *cn = (xcb_configure_notify_event_t *)event;\n                xcb_ctx->width = cn->width;\n                xcb_ctx->height = cn->height;\n                events |= NK_XCB_EVENT_RESIZED;\n            }\n            break;\n        case XCB_KEYMAP_NOTIFY:\n            /* xcb_refresh_keyboard_mapping(xcb_ctx->key_symbols, (xcb_mapping_notify_event_t *)event); */\n            break;\n        case XCB_EXPOSE:\n        case XCB_REPARENT_NOTIFY:\n        case XCB_MAP_NOTIFY:\n            events |= NK_XCB_EVENT_PAINT;\n            break;\n        case XCB_CLIENT_MESSAGE:\n            {\n                xcb_client_message_event_t *cm = (xcb_client_message_event_t *)event;\n                if (cm->data.data32[0] == xcb_ctx->del_atom->atom)\n                {\n                    events = NK_XCB_EVENT_STOP;\n                }\n                else\n                {\n                    xcb_ctx->last_client_message = *cm;\n                    events = NK_XCB_CLIENT_MESSAGE;\n                }\n            }\n            break;\n        default:\n            printf (\"Unhandled event: %s\\n\", xcb_event_get_label(event->response_type));\n            break;\n        }\n        free(event);\n    }\n    while ((events != NK_XCB_EVENT_STOP) && (event = xcb_poll_for_event(xcb_ctx->conn)));\n    nk_input_end(nk_ctx);\n\n    return events;\n}\n\nNK_API void nk_xcb_render(struct nk_xcb_context *xcb_ctx)\n{\n    xcb_flush (xcb_ctx->conn);\n\n#ifdef NK_XCB_MIN_FRAME_TIME\n    {\n        struct timespec tp;\n        unsigned long spent;\n        clock_gettime(CLOCK_MONOTONIC_COARSE, &tp);\n        spent = tp.tv_sec * NK_XCB_NSEC + tp.tv_nsec - xcb_ctx->last_render;\n        if (NK_XCB_MIN_FRAME_TIME > spent) {\n            tp.tv_sec = 0;\n            tp.tv_nsec = NK_XCB_MIN_FRAME_TIME - spent;\n            while (clock_nanosleep(CLOCK_MONOTONIC, 0, &tp, &tp) == EINTR);\n        }\n    }\n#endif /* NK_XCB_MIN_FRAME_TIME */\n}\n\nNK_API void nk_xcb_size(struct nk_xcb_context *xcb_ctx, int *width, int *height)\n{\n    *width = xcb_ctx->width;\n    *height = xcb_ctx->height;\n}\n\nNK_API void *nk_xcb_create_cairo_surface(struct nk_xcb_context *xcb_ctx)\n{\n    xcb_screen_t *screen;\n    xcb_visualtype_t *visual;\n\n    screen = xcb_aux_get_screen(xcb_ctx->conn, xcb_ctx->screennum);\n    visual = xcb_aux_get_visualtype(xcb_ctx->conn, xcb_ctx->screennum, screen->root_visual);\n    return cairo_xcb_surface_create(xcb_ctx->conn, xcb_ctx->window, visual, xcb_ctx->width, xcb_ctx->height);\n}\n\nNK_API void nk_xcb_resize_cairo_surface(struct nk_xcb_context *xcb_ctx, void *surface)\n{\n    cairo_xcb_surface_set_size((cairo_surface_t *)surface, xcb_ctx->width, xcb_ctx->height);\n}\n\n\n\n#define NK_TO_CAIRO(x) ((double) x / 255.0)\n\n\nNK_INTERN float nk_cairo_text_width(nk_handle handle, float height __attribute__ ((__unused__)), const char *text, int len)\n{\n    cairo_scaled_font_t *font = (cairo_scaled_font_t *)handle.ptr;\n    cairo_glyph_t *glyphs = NULL;\n    int num_glyphs;\n    cairo_text_extents_t extents;\n\n    cairo_scaled_font_text_to_glyphs(font, 0, 0, text, len, &glyphs, &num_glyphs, NULL, NULL, NULL);\n    cairo_scaled_font_glyph_extents(font, glyphs, num_glyphs, &extents);\n    cairo_glyph_free(glyphs);\n\n    return extents.x_advance;\n}\n\nNK_API struct nk_cairo_context *nk_cairo_init(struct nk_color *bg, const char *font_file, double font_size, void *surf)\n{\n    cairo_surface_t *surface = (cairo_surface_t *)surf;\n    struct nk_cairo_context *cairo_ctx;\n    cairo_t *cr;\n    cairo_font_extents_t extents;\n    cairo_scaled_font_t *default_font;\n    struct nk_user_font *font;\n\n    cr = cairo_create(surface);\n    font = (struct nk_user_font *)malloc(sizeof (struct nk_user_font));\n    if (font_file != NULL) {\n        FT_Library library;\n        FT_Face face;\n        cairo_font_face_t *font_face;\n        static const cairo_user_data_key_t key = {0};\n\n        FT_Init_FreeType(&library);\n        FT_New_Face(library, font_file, 0, &face);\n        font_face = cairo_ft_font_face_create_for_ft_face(face, 0);\n        cairo_font_face_set_user_data(font_face, &key, face, (cairo_destroy_func_t)FT_Done_Face);\n        cairo_set_font_face(cr, font_face);\n    }\n    if (font_size < 0.01) {\n        font_size = 11.0;\n    }\n    cairo_set_font_size(cr, font_size);\n    default_font = cairo_get_scaled_font(cr);\n    cairo_scaled_font_extents(default_font, &extents);\n    font->userdata.ptr = default_font;\n    font->height = extents.height;\n    font->width = nk_cairo_text_width;\n\n    cairo_ctx = (struct nk_cairo_context *)malloc(sizeof(struct nk_cairo_context));\n    cairo_ctx->surface = (cairo_surface_t *)surface;\n    cairo_ctx->cr = cr;\n    cairo_ctx->font = font;\n    cairo_ctx->bg = bg;\n    cairo_ctx->last_buffer = NULL;\n    cairo_ctx->buffer_size = 0;\n    cairo_ctx->repaint = nk_false;\n\n    return cairo_ctx;\n}\n\nNK_API cairo_surface_t *nk_cairo_surface(struct nk_cairo_context *cairo_ctx)\n{\n    return cairo_ctx->surface;\n}\n\nNK_API struct nk_user_font *nk_cairo_default_font(struct nk_cairo_context *cairo_ctx)\n{\n    return cairo_ctx->font;\n}\n\nNK_API void nk_cairo_free(struct nk_cairo_context *cairo_ctx)\n{\n    free (cairo_ctx->last_buffer);\n    cairo_destroy(cairo_ctx->cr);\n    cairo_surface_destroy(cairo_ctx->surface);\n    free(cairo_ctx->font);\n    free(cairo_ctx);\n}\n\nNK_API void nk_cairo_damage(struct nk_cairo_context *cairo_ctx)\n{\n    cairo_ctx->repaint = nk_true;\n}\n\nNK_API int nk_cairo_render(struct nk_cairo_context *cairo_ctx, struct nk_context *nk_ctx)\n{\n    cairo_t *cr;\n    const struct nk_command *cmd = NULL;\n    void *cmds = nk_buffer_memory(&nk_ctx->memory);\n\n    if (cairo_ctx->buffer_size != nk_ctx->memory.allocated) {\n        cairo_ctx->buffer_size = nk_ctx->memory.allocated;\n        cairo_ctx->last_buffer = realloc(cairo_ctx->last_buffer, cairo_ctx->buffer_size);\n        memcpy(cairo_ctx->last_buffer, cmds, cairo_ctx->buffer_size);\n    }\n    else if (!memcmp(cmds, cairo_ctx->last_buffer, cairo_ctx->buffer_size)) {\n        if (!cairo_ctx->repaint) {\n            return nk_false;\n        }\n        cairo_ctx->repaint = nk_false;\n    }\n    else {\n        memcpy(cairo_ctx->last_buffer, cmds, cairo_ctx->buffer_size);\n    }\n\n    cr = cairo_ctx->cr;\n    cairo_push_group(cr);\n\n    cairo_set_source_rgb(cr, NK_TO_CAIRO(cairo_ctx->bg->r), NK_TO_CAIRO(cairo_ctx->bg->g), NK_TO_CAIRO(cairo_ctx->bg->b));\n    cairo_paint(cr);\n\n    nk_foreach(cmd, nk_ctx) {\n        switch (cmd->type) {\n        case NK_COMMAND_NOP:\n            break;\n        case NK_COMMAND_SCISSOR:\n            {\n                const struct nk_command_scissor *s = (const struct nk_command_scissor *)cmd;\n                cairo_reset_clip(cr);\n                if (s->x >= 0) {\n                    cairo_rectangle(cr, s->x - 1, s->y - 1, s->w + 2, s->h + 2);\n                    cairo_clip(cr);\n                }\n            }\n            break;\n        case NK_COMMAND_LINE:\n            {\n                const struct nk_command_line *l = (const struct nk_command_line *)cmd;\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(l->color.r), NK_TO_CAIRO(l->color.g), NK_TO_CAIRO(l->color.b), NK_TO_CAIRO(l->color.a));\n                cairo_set_line_width(cr, l->line_thickness);\n                cairo_move_to(cr, l->begin.x, l->begin.y);\n                cairo_line_to(cr, l->end.x, l->end.y);\n                cairo_stroke(cr);\n            }\n            break;\n        case NK_COMMAND_CURVE:\n            {\n                const struct nk_command_curve *q = (const struct nk_command_curve *)cmd;\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(q->color.r), NK_TO_CAIRO(q->color.g), NK_TO_CAIRO(q->color.b), NK_TO_CAIRO(q->color.a));\n                cairo_set_line_width(cr, q->line_thickness);\n                cairo_move_to(cr, q->begin.x, q->begin.y);\n                cairo_curve_to(cr, q->ctrl[0].x, q->ctrl[0].y, q->ctrl[1].x, q->ctrl[1].y, q->end.x, q->end.y);\n                cairo_stroke(cr);\n            }\n            break;\n        case NK_COMMAND_RECT:\n            {\n                const struct nk_command_rect *r = (const struct nk_command_rect *)cmd;\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(r->color.r), NK_TO_CAIRO(r->color.g), NK_TO_CAIRO(r->color.b), NK_TO_CAIRO(r->color.a));\n                cairo_set_line_width(cr, r->line_thickness);\n                if (r->rounding == 0) {\n                    cairo_rectangle(cr, r->x, r->y, r->w, r->h);\n                }\n                else {\n                    int xl = r->x + r->w - r->rounding;\n                    int xr = r->x + r->rounding;\n                    int yl = r->y + r->h - r->rounding;\n                    int yr = r->y + r->rounding;\n                    cairo_new_sub_path(cr);\n                    cairo_arc(cr, xl, yr, r->rounding, NK_XCB_DEG_TO_RAD(-90), NK_XCB_DEG_TO_RAD(0));\n                    cairo_arc(cr, xl, yl, r->rounding, NK_XCB_DEG_TO_RAD(0), NK_XCB_DEG_TO_RAD(90));\n                    cairo_arc(cr, xr, yl, r->rounding, NK_XCB_DEG_TO_RAD(90), NK_XCB_DEG_TO_RAD(180));\n                    cairo_arc(cr, xr, yr, r->rounding, NK_XCB_DEG_TO_RAD(180), NK_XCB_DEG_TO_RAD(270));\n                    cairo_close_path(cr);\n                }\n                cairo_stroke(cr);\n            }\n            break;\n        case NK_COMMAND_RECT_FILLED:\n            {\n                const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled *)cmd;\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(r->color.r), NK_TO_CAIRO(r->color.g), NK_TO_CAIRO(r->color.b), NK_TO_CAIRO(r->color.a));\n                if (r->rounding == 0) {\n                    cairo_rectangle(cr, r->x, r->y, r->w, r->h);\n                } else {\n                    int xl = r->x + r->w - r->rounding;\n                    int xr = r->x + r->rounding;\n                    int yl = r->y + r->h - r->rounding;\n                    int yr = r->y + r->rounding;\n                    cairo_new_sub_path(cr);\n                    cairo_arc(cr, xl, yr, r->rounding, NK_XCB_DEG_TO_RAD(-90), NK_XCB_DEG_TO_RAD(0));\n                    cairo_arc(cr, xl, yl, r->rounding, NK_XCB_DEG_TO_RAD(0), NK_XCB_DEG_TO_RAD(90));\n                    cairo_arc(cr, xr, yl, r->rounding, NK_XCB_DEG_TO_RAD(90), NK_XCB_DEG_TO_RAD(180));\n                    cairo_arc(cr, xr, yr, r->rounding, NK_XCB_DEG_TO_RAD(180), NK_XCB_DEG_TO_RAD(270));\n                    cairo_close_path(cr);\n                }\n                cairo_fill(cr);\n            }\n            break;\n        case NK_COMMAND_RECT_MULTI_COLOR:\n            {\n                /* from https://github.com/taiwins/twidgets/blob/master/src/nk_wl_cairo.c */\n                const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color *)cmd;\n                cairo_pattern_t *pat = cairo_pattern_create_mesh();\n                if (pat) {\n                    cairo_mesh_pattern_begin_patch(pat);\n                    cairo_mesh_pattern_move_to(pat, r->x, r->y);\n                    cairo_mesh_pattern_line_to(pat, r->x, r->y + r->h);\n                    cairo_mesh_pattern_line_to(pat, r->x + r->w, r->y + r->h);\n                    cairo_mesh_pattern_line_to(pat, r->x + r->w, r->y);\n                    cairo_mesh_pattern_set_corner_color_rgba(pat, 0, NK_TO_CAIRO(r->left.r), NK_TO_CAIRO(r->left.g), NK_TO_CAIRO(r->left.b), NK_TO_CAIRO(r->left.a));\n                    cairo_mesh_pattern_set_corner_color_rgba(pat, 1, NK_TO_CAIRO(r->bottom.r), NK_TO_CAIRO(r->bottom.g), NK_TO_CAIRO(r->bottom.b), NK_TO_CAIRO(r->bottom.a));\n                    cairo_mesh_pattern_set_corner_color_rgba(pat, 2, NK_TO_CAIRO(r->right.r), NK_TO_CAIRO(r->right.g), NK_TO_CAIRO(r->right.b), NK_TO_CAIRO(r->right.a));\n                    cairo_mesh_pattern_set_corner_color_rgba(pat, 3, NK_TO_CAIRO(r->top.r), NK_TO_CAIRO(r->top.g), NK_TO_CAIRO(r->top.b), NK_TO_CAIRO(r->top.a));\n                    cairo_mesh_pattern_end_patch(pat);\n\n                    cairo_rectangle(cr, r->x, r->y, r->w, r->h);\n                    cairo_set_source(cr, pat);\n                    cairo_fill(cr);\n                    cairo_pattern_destroy(pat);\n                }\n            }\n            break;\n        case NK_COMMAND_CIRCLE:\n            {\n                const struct nk_command_circle *c = (const struct nk_command_circle *)cmd;\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(c->color.r), NK_TO_CAIRO(c->color.g), NK_TO_CAIRO(c->color.b), NK_TO_CAIRO(c->color.a));\n                cairo_set_line_width(cr, c->line_thickness);\n                cairo_save(cr);\n                cairo_translate(cr, c->x + c->w / 2.0, c->y + c->h / 2.0);\n                cairo_scale(cr, c->w / 2.0, c->h / 2.0);\n                cairo_arc(cr, 0, 0, 1, NK_XCB_DEG_TO_RAD(0), NK_XCB_DEG_TO_RAD(360));\n                cairo_restore(cr);\n                cairo_stroke(cr);\n            }\n            break;\n        case NK_COMMAND_CIRCLE_FILLED:\n            {\n                const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(c->color.r), NK_TO_CAIRO(c->color.g), NK_TO_CAIRO(c->color.b), NK_TO_CAIRO(c->color.a));\n                cairo_save(cr);\n                cairo_translate(cr, c->x + c->w / 2.0, c->y + c->h / 2.0);\n                cairo_scale(cr, c->w / 2.0, c->h / 2.0);\n                cairo_arc(cr, 0, 0, 1, NK_XCB_DEG_TO_RAD(0), NK_XCB_DEG_TO_RAD(360));\n                cairo_restore(cr);\n                cairo_fill(cr);\n            }\n            break;\n        case NK_COMMAND_ARC:\n            {\n                const struct nk_command_arc *a = (const struct nk_command_arc*) cmd;\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(a->color.r), NK_TO_CAIRO(a->color.g), NK_TO_CAIRO(a->color.b), NK_TO_CAIRO(a->color.a));\n                cairo_set_line_width(cr, a->line_thickness);\n                cairo_arc(cr, a->cx, a->cy, a->r, NK_XCB_DEG_TO_RAD(a->a[0]), NK_XCB_DEG_TO_RAD(a->a[1]));\n                cairo_stroke(cr);\n            }\n            break;\n        case NK_COMMAND_ARC_FILLED:\n            {\n                const struct nk_command_arc_filled *a = (const struct nk_command_arc_filled*)cmd;\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(a->color.r), NK_TO_CAIRO(a->color.g), NK_TO_CAIRO(a->color.b), NK_TO_CAIRO(a->color.a));\n                cairo_arc(cr, a->cx, a->cy, a->r, NK_XCB_DEG_TO_RAD(a->a[0]), NK_XCB_DEG_TO_RAD(a->a[1]));\n                cairo_fill(cr);\n            }\n            break;\n        case NK_COMMAND_TRIANGLE:\n            {\n                const struct nk_command_triangle *t = (const struct nk_command_triangle *)cmd;\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(t->color.r), NK_TO_CAIRO(t->color.g), NK_TO_CAIRO(t->color.b), NK_TO_CAIRO(t->color.a));\n                cairo_set_line_width(cr, t->line_thickness);\n                cairo_move_to(cr, t->a.x, t->a.y);\n                cairo_line_to(cr, t->b.x, t->b.y);\n                cairo_line_to(cr, t->c.x, t->c.y);\n                cairo_close_path(cr);\n                cairo_stroke(cr);\n            }\n            break;\n        case NK_COMMAND_TRIANGLE_FILLED:\n            {\n                const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled *)cmd;\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(t->color.r), NK_TO_CAIRO(t->color.g), NK_TO_CAIRO(t->color.b), NK_TO_CAIRO(t->color.a));\n                cairo_move_to(cr, t->a.x, t->a.y);\n                cairo_line_to(cr, t->b.x, t->b.y);\n                cairo_line_to(cr, t->c.x, t->c.y);\n                cairo_close_path(cr);\n                cairo_fill(cr);\n            }\n            break;\n        case NK_COMMAND_POLYGON:\n            {\n                int i;\n                const struct nk_command_polygon *p = (const struct nk_command_polygon *)cmd;\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(p->color.r), NK_TO_CAIRO(p->color.g), NK_TO_CAIRO(p->color.b), NK_TO_CAIRO(p->color.a));\n                cairo_set_line_width(cr, p->line_thickness);\n                cairo_move_to(cr, p->points[0].x, p->points[0].y);\n                for (i = 1; i < p->point_count; ++i) {\n                    cairo_line_to(cr, p->points[i].x, p->points[i].y);\n                }\n                cairo_close_path(cr);\n                cairo_stroke(cr);\n            }\n            break;\n        case NK_COMMAND_POLYGON_FILLED:\n            {\n                int i;\n                const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled *)cmd;\n                cairo_set_source_rgba (cr, NK_TO_CAIRO(p->color.r), NK_TO_CAIRO(p->color.g), NK_TO_CAIRO(p->color.b), NK_TO_CAIRO(p->color.a));\n                cairo_move_to(cr, p->points[0].x, p->points[0].y);\n                for (i = 1; i < p->point_count; ++i) {\n                    cairo_line_to(cr, p->points[i].x, p->points[i].y);\n                }\n                cairo_close_path(cr);\n                cairo_fill(cr);\n            }\n            break;\n        case NK_COMMAND_POLYLINE:\n            {\n                int i;\n                const struct nk_command_polyline *p = (const struct nk_command_polyline *)cmd;\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(p->color.r), NK_TO_CAIRO(p->color.g), NK_TO_CAIRO(p->color.b), NK_TO_CAIRO(p->color.a));\n                cairo_set_line_width(cr, p->line_thickness);\n                cairo_move_to(cr, p->points[0].x, p->points[0].y);\n                for (i = 1; i < p->point_count; ++i) {\n                    cairo_line_to(cr, p->points[i].x, p->points[i].y);\n                }\n                cairo_stroke(cr);\n            }\n            break;\n        case NK_COMMAND_TEXT:\n            {\n                const struct nk_command_text *t = (const struct nk_command_text *)cmd;\n                cairo_glyph_t *glyphs = NULL;\n                int num_glyphs;\n                cairo_text_cluster_t *clusters = NULL;\n                int num_clusters;\n                cairo_text_cluster_flags_t cluster_flags;\n                cairo_font_extents_t extents;\n\n                cairo_set_source_rgba(cr, NK_TO_CAIRO(t->foreground.r), NK_TO_CAIRO(t->foreground.g), NK_TO_CAIRO(t->foreground.b), NK_TO_CAIRO(t->foreground.a));\n                cairo_scaled_font_extents((cairo_scaled_font_t *)t->font->userdata.ptr, &extents);\n                cairo_scaled_font_text_to_glyphs((cairo_scaled_font_t *)t->font->userdata.ptr,\n                        t->x, t->y + extents.ascent, t->string, t->length,\n                        &glyphs, &num_glyphs, &clusters, &num_clusters,\n                        &cluster_flags);\n                cairo_show_text_glyphs(cr, t->string, t->length, glyphs,\n                        num_glyphs, clusters, num_clusters,\n                        cluster_flags);\n                cairo_glyph_free(glyphs);\n                cairo_text_cluster_free(clusters);\n            }\n            break;\n        case NK_COMMAND_IMAGE:\n            {\n                /* from https://github.com/taiwins/twidgets/blob/master/src/nk_wl_cairo.c */\n                const struct nk_command_image *im = (const struct nk_command_image *)cmd;\n                cairo_surface_t *img_surf;\n                double sw = (double)im->w / (double)im->img.region[2];\n                double sh = (double)im->h / (double)im->img.region[3];\n                cairo_format_t format = CAIRO_FORMAT_ARGB32;\n                int stride = cairo_format_stride_for_width(format, im->img.w);\n\n                if (!im->img.handle.ptr) return nk_false;\n                img_surf = cairo_image_surface_create_for_data((unsigned char *)im->img.handle.ptr, format, im->img.w, im->img.h, stride);\n                if (!img_surf) return nk_false;\n                cairo_save(cr);\n\n                cairo_rectangle(cr, im->x, im->y, im->w, im->h);\n                /* scale here, if after source set, the scale would not apply to source\n                 * surface\n                 */\n                cairo_scale(cr, sw, sh);\n                /* the coordinates system in cairo is not intuitive, scale, translate,\n                 * are applied to source. Refer to\n                 * \"https://www.cairographics.org/FAQ/#paint_from_a_surface\" for details\n                 *\n                 * if you set source_origin to (0,0), it would be like source origin\n                 * aligned to dest origin, then if you draw a rectangle on (x, y, w, h).\n                 * it would clip out the (x, y, w, h) of the source on you dest as well.\n                 */\n                cairo_set_source_surface(cr, img_surf, im->x/sw - im->img.region[0], im->y/sh - im->img.region[1]);\n                cairo_fill(cr);\n\n                cairo_restore(cr);\n                cairo_surface_destroy(img_surf);\n            }\n            break;\n        case NK_COMMAND_CUSTOM:\n            {\n\t            const struct nk_command_custom *cu = (const struct nk_command_custom *)cmd;\n                if (cu->callback) {\n                    cu->callback(cr, cu->x, cu->y, cu->w, cu->h, cu->callback_data);\n                }\n            }\n        default:\n            break;\n        }\n    }\n\n    cairo_pop_group_to_source(cr);\n    cairo_paint(cr);\n    cairo_surface_flush(cairo_ctx->surface);\n\n    return nk_true;\n}\n\nNK_INTERN xkbcommon_context *xkbcommon_init(xcb_connection_t *conn)\n{\n\txkbcommon_context *kbdctx;\n\tint32_t device_id;\n\n\tint ret = xkb_x11_setup_xkb_extension(conn,\n\t\tXKB_X11_MIN_MAJOR_XKB_VERSION,\n\t\tXKB_X11_MIN_MINOR_XKB_VERSION,\n\t\tXKB_X11_SETUP_XKB_EXTENSION_NO_FLAGS,\n\t\tNULL, NULL, NULL, NULL);\n\n    if (ret == 0)\n\t{\n\t\treturn NULL;\n\t}\n\n\tkbdctx = (xkbcommon_context *)malloc(sizeof(xkbcommon_context));\n\tkbdctx->ctx = NULL;\n\tkbdctx->keymap = NULL;\n\tkbdctx->state = NULL;\n\n\tkbdctx->ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);\n    if (!kbdctx->ctx)\n\t{\n\t\txkbcommon_free(kbdctx);\n\t\treturn NULL;\n\t}\n\n\tdevice_id = xkb_x11_get_core_keyboard_device_id(conn);\n\tif (device_id == -1)\n\t{\n\t\txkbcommon_free(kbdctx);\n\t\treturn NULL;\n\t}\n\n\tkbdctx->keymap = xkb_x11_keymap_new_from_device(kbdctx->ctx, conn, device_id, XKB_KEYMAP_COMPILE_NO_FLAGS);\n\tif (!kbdctx->keymap)\n\t{\n\t\txkbcommon_free(kbdctx);\n\t\treturn NULL;\n\t}\n\n\tkbdctx->state = xkb_x11_state_new_from_device(kbdctx->keymap, conn, device_id);\n\tif (!kbdctx->state)\n\t{\n\t\txkbcommon_free(kbdctx);\n\t\treturn NULL;\n\t}\n\n\treturn kbdctx;\n}\n\nNK_INTERN void xkbcommon_free(xkbcommon_context *kbdctx)\n{\n\tif (kbdctx != NULL)\n\t{\n\t\tif (kbdctx->state) xkb_state_unref(kbdctx->state);\n\t\tif (kbdctx->keymap) xkb_keymap_unref(kbdctx->keymap);\n\t\tif (kbdctx->ctx) xkb_context_unref(kbdctx->ctx);\n\n\t\tkbdctx->ctx = NULL;\n\t\tkbdctx->keymap = NULL;\n\t\tkbdctx->state = NULL;\n\n\t\tfree(kbdctx);\n\t}\n}\n\nNK_INTERN xkb_keysym_t keycode_to_keysym(nk_xcb_context *ctx, xkb_keycode_t keycode, int pressed)\n{\n\txkb_keysym_t keysym;\n\txkbcommon_context *kbdctx = ctx->xkbcommon_ctx;\n\n\tif (kbdctx != NULL)\n\t{\n\t\tkeysym = xkb_state_key_get_one_sym(kbdctx->state, keycode);\n\n\t\t/*xkb_state_component changed = */\n\t\t\txkb_state_update_key(kbdctx->state, keycode, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);\n\t}\n\telse\n\t{\n\t\tkeysym = 0;\n\t}\n\n\treturn keysym;\n}\n\n#endif /* NK_XCB_CAIRO_IMPLEMENTATION */\n"
  },
  {
    "path": "example/Makefile",
    "content": "# Flags\nCFLAGS += -std=c99 -Wall -Wextra -pedantic -Wno-misleading-indentation -Wno-shift-negative-value\nLIBS :=\n\nifeq ($(OS),Windows_NT)\n\tDEL_BIN = IF EXIST bin DEL /F /Q bin\\*\n\tBIN := $(BIN).exe\n\tLIBS := -lglfw3 -lopengl32 -lm -lGLU32 -lGLEW32\nelse\n\tDEL_BIN = rm -rf bin\n\tUNAME_S := $(shell uname -s)\n\tGLFW3 := $(shell pkg-config --libs glfw3)\n\tifeq ($(UNAME_S),Darwin)\n\t\tLIBS := $(GLFW3) -framework OpenGL -framework Cocoa -framework IOKit -framework CoreVideo -lm -lGLEW -L/usr/local/lib\n\t\tCFLAGS += -I/usr/local/include\n\telse\n\t\tLIBS := $(GLFW3) -lGL -lm -lGLU -lGLEW\n\tendif\nendif\n\nall: generate file_browser extended canvas skinning\n\ngenerate: clean\nifeq ($(OS),Windows_NT)\n\t@mkdir bin 2> nul || exit 0\nelse\n\t@mkdir -p bin\nendif\n\nclean:\n\t$(DEL_BIN)\n\nfile_browser: generate\n\t$(CC) $(CFLAGS) -o bin/file_browser file_browser.c $(LIBS)\n\nextended: generate\n\t$(CC) $(CFLAGS) -o bin/extended extended.c $(LIBS)\n\ncanvas: generate\n\t$(CC) $(CFLAGS) -o bin/canvas canvas.c $(LIBS)\n\nskinning: generate\n\t$(CC) $(CFLAGS) -o bin/skinning skinning.c $(LIBS)\n\n"
  },
  {
    "path": "example/canvas.c",
    "content": "/* nuklear - v1.05 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <time.h>\n#include <limits.h>\n\n#include <GL/glew.h>\n#include <GLFW/glfw3.h>\n\n#define NK_PRIVATE\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#include \"../nuklear.h\"\n\n#define STB_IMAGE_IMPLEMENTATION\n#include \"stb_image.h\"\n\n/* macros */\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define MAX_VERTEX_MEMORY 512 * 1024\n#define MAX_ELEMENT_MEMORY 128 * 1024\n\n#define UNUSED(a) (void)a\n#define MIN(a,b) ((a) < (b) ? (a) : (b))\n#define MAX(a,b) ((a) < (b) ? (b) : (a))\n#define LEN(a) (sizeof(a)/sizeof(a)[0])\n\n#define NK_SHADER_VERSION \"#version 150\\n\"\n\n/* ===============================================================\n *\n *                          DEVICE\n *\n * ===============================================================*/\nstruct nk_glfw_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstruct device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint vbo, vao, ebo;\n    GLuint prog;\n    GLuint vert_shdr;\n    GLuint frag_shdr;\n    GLint attrib_pos;\n    GLint attrib_uv;\n    GLint attrib_col;\n    GLint uniform_tex;\n    GLint uniform_proj;\n    GLuint font_tex;\n};\n\n/* function icon_load () is not used to build this file but might still be useful :) */\n/*\nstatic void\ndie(const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    fputs(\"\\n\", stderr);\n    exit(EXIT_FAILURE);\n}\n\nstatic struct nk_image\nicon_load(const char *filename)\n{\n    int x,y,n;\n    GLuint tex;\n    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);\n    if (!data) die(\"[SDL]: failed to load image: %s\", filename);\n\n     glGenTextures(1, &tex);\n    glBindTexture(GL_TEXTURE_2D, tex);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);\n    glGenerateMipmap(GL_TEXTURE_2D);\n    stbi_image_free(data);\n    return nk_image_id((int)tex);\n}\n*/\n\nstatic void\ndevice_init(struct device *dev)\n{\n    GLint status;\n    static const GLchar *vertex_shader =\n        NK_SHADER_VERSION\n        \"uniform mat4 ProjMtx;\\n\"\n        \"in vec2 Position;\\n\"\n        \"in vec2 TexCoord;\\n\"\n        \"in vec4 Color;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main() {\\n\"\n        \"   Frag_UV = TexCoord;\\n\"\n        \"   Frag_Color = Color;\\n\"\n        \"   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\\n\"\n        \"}\\n\";\n    static const GLchar *fragment_shader =\n        NK_SHADER_VERSION\n        \"precision mediump float;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"out vec4 Out_Color;\\n\"\n        \"void main(){\\n\"\n        \"   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    nk_buffer_init_default(&dev->cmds);\n    dev->prog = glCreateProgram();\n    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);\n    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);\n    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);\n    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);\n    glCompileShader(dev->vert_shdr);\n    glCompileShader(dev->frag_shdr);\n    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glAttachShader(dev->prog, dev->vert_shdr);\n    glAttachShader(dev->prog, dev->frag_shdr);\n    glLinkProgram(dev->prog);\n    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);\n    assert(status == GL_TRUE);\n\n    dev->uniform_tex = glGetUniformLocation(dev->prog, \"Texture\");\n    dev->uniform_proj = glGetUniformLocation(dev->prog, \"ProjMtx\");\n    dev->attrib_pos = glGetAttribLocation(dev->prog, \"Position\");\n    dev->attrib_uv = glGetAttribLocation(dev->prog, \"TexCoord\");\n    dev->attrib_col = glGetAttribLocation(dev->prog, \"Color\");\n\n    {\n        /* buffer setup */\n        GLsizei vs = sizeof(struct nk_glfw_vertex);\n        size_t vp = offsetof(struct nk_glfw_vertex, position);\n        size_t vt = offsetof(struct nk_glfw_vertex, uv);\n        size_t vc = offsetof(struct nk_glfw_vertex, col);\n\n        glGenBuffers(1, &dev->vbo);\n        glGenBuffers(1, &dev->ebo);\n        glGenVertexArrays(1, &dev->vao);\n\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glEnableVertexAttribArray((GLuint)dev->attrib_pos);\n        glEnableVertexAttribArray((GLuint)dev->attrib_uv);\n        glEnableVertexAttribArray((GLuint)dev->attrib_col);\n\n        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);\n        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);\n        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);\n    }\n\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n}\n\nstatic void\ndevice_upload_atlas(struct device *dev, const void *image, int width, int height)\n{\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nstatic void\ndevice_shutdown(struct device *dev)\n{\n    glDetachShader(dev->prog, dev->vert_shdr);\n    glDetachShader(dev->prog, dev->frag_shdr);\n    glDeleteShader(dev->vert_shdr);\n    glDeleteShader(dev->frag_shdr);\n    glDeleteProgram(dev->prog);\n    glDeleteTextures(1, &dev->font_tex);\n    glDeleteBuffers(1, &dev->vbo);\n    glDeleteBuffers(1, &dev->ebo);\n    nk_buffer_free(&dev->cmds);\n}\n\nstatic void\ndevice_draw(struct device *dev, struct nk_context *ctx, int width, int height,\n    enum nk_anti_aliasing AA)\n{\n    GLfloat ortho[4][4] = {\n        {2.0f, 0.0f, 0.0f, 0.0f},\n        {0.0f,-2.0f, 0.0f, 0.0f},\n        {0.0f, 0.0f,-1.0f, 0.0f},\n        {-1.0f,1.0f, 0.0f, 1.0f},\n    };\n    ortho[0][0] /= (GLfloat)width;\n    ortho[1][1] /= (GLfloat)height;\n\n    /* setup global state */\n    glEnable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glActiveTexture(GL_TEXTURE0);\n\n    /* setup program */\n    glUseProgram(dev->prog);\n    glUniform1i(dev->uniform_tex, 0);\n    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        void *vertices, *elements;\n        const nk_draw_index *offset = NULL;\n\n        /* allocate vertex and element buffer */\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);\n\n        /* load draw vertices & elements directly into vertex + element buffer */\n        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);\n        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n                {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},\n                {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},\n                {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},\n                {NK_VERTEX_LAYOUT_END}\n            };\n            NK_MEMSET(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_glfw_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            {struct nk_buffer vbuf, ebuf;\n            nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);\n            nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);\n            nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}\n        }\n        glUnmapBuffer(GL_ARRAY_BUFFER);\n        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);\n\n      /* iterate over and execute each draw command */\n        nk_draw_foreach(cmd, ctx, &dev->cmds)\n        {\n            if (!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor(\n                (GLint)(cmd->clip_rect.x),\n                (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h))),\n                (GLint)(cmd->clip_rect.w),\n                (GLint)(cmd->clip_rect.h));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(ctx);\n        nk_buffer_clear(&dev->cmds);\n    }\n\n    /* default OpenGL state */\n    glUseProgram(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n    glDisable(GL_BLEND);\n    glDisable(GL_SCISSOR_TEST);\n}\n\n/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/\nstatic void error_callback(int e, const char *d){printf(\"Error %d: %s\\n\", e, d);}\nstatic void text_input(GLFWwindow *win, unsigned int codepoint)\n{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}\nstatic void scroll_input(GLFWwindow *win, double _, double yoff)\n{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));}\n\nstatic void\npump_input(struct nk_context *ctx, GLFWwindow *win)\n{\n    double x, y;\n    nk_input_begin(ctx);\n    glfwPollEvents();\n\n    nk_input_key(ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);\n    nk_input_key(ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);\n\n    if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||\n        glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {\n        nk_input_key(ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);\n        nk_input_key(ctx, NK_KEY_SHIFT, 1);\n    } else {\n        nk_input_key(ctx, NK_KEY_COPY, 0);\n        nk_input_key(ctx, NK_KEY_PASTE, 0);\n        nk_input_key(ctx, NK_KEY_CUT, 0);\n        nk_input_key(ctx, NK_KEY_SHIFT, 0);\n    }\n\n    glfwGetCursorPos(win, &x, &y);\n    nk_input_motion(ctx, (int)x, (int)y);\n    nk_input_button(ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);\n    nk_input_button(ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);\n    nk_input_end(ctx);\n}\n\nstruct nk_canvas {\n    struct nk_command_buffer *painter;\n    struct nk_vec2 item_spacing;\n    struct nk_vec2 panel_padding;\n    struct nk_style_item window_background;\n};\n\nstatic void\ncanvas_begin(struct nk_context *ctx, struct nk_canvas *canvas, nk_flags flags,\n    int x, int y, int width, int height, struct nk_color background_color)\n{\n    /* save style properties which will be overwritten */\n    canvas->panel_padding = ctx->style.window.padding;\n    canvas->item_spacing = ctx->style.window.spacing;\n    canvas->window_background = ctx->style.window.fixed_background;\n\n    /* use the complete window space and set background */\n    ctx->style.window.spacing = nk_vec2(0,0);\n    ctx->style.window.padding = nk_vec2(0,0);\n    ctx->style.window.fixed_background = nk_style_item_color(background_color);\n\n    /* create/update window and set position + size */\n    flags = flags & ~NK_WINDOW_DYNAMIC;\n    nk_window_set_bounds(ctx, \"Window\", nk_rect(x, y, width, height));\n    nk_begin(ctx, \"Window\", nk_rect(x, y, width, height), NK_WINDOW_NO_SCROLLBAR|flags);\n\n    /* allocate the complete window space for drawing */\n    {struct nk_rect total_space;\n    total_space = nk_window_get_content_region(ctx);\n    nk_layout_row_dynamic(ctx, total_space.h, 1);\n    nk_widget(&total_space, ctx);\n    canvas->painter = nk_window_get_canvas(ctx);}\n}\n\nstatic void\ncanvas_end(struct nk_context *ctx, struct nk_canvas *canvas)\n{\n    nk_end(ctx);\n    ctx->style.window.spacing = canvas->panel_padding;\n    ctx->style.window.padding = canvas->item_spacing;\n    ctx->style.window.fixed_background = canvas->window_background;\n}\n\nint main(int argc, char *argv[])\n{\n    /* Platform */\n    static GLFWwindow *win;\n    int width = 0, height = 0;\n\n    /* GUI */\n    struct device device;\n    struct nk_font_atlas atlas;\n    struct nk_context ctx;\n\n    NK_UNUSED(argc);\n    NK_UNUSED(argv);\n\n    /* GLFW */\n    glfwSetErrorCallback(error_callback);\n    if (!glfwInit()) {\n        fprintf(stdout, \"[GFLW] failed to init!\\n\");\n        exit(1);\n    }\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);\n    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);\n    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);\n    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, \"Demo\", NULL, NULL);\n    glfwMakeContextCurrent(win);\n    glfwSetWindowUserPointer(win, &ctx);\n    glfwSetCharCallback(win, text_input);\n    glfwSetScrollCallback(win, scroll_input);\n    glfwGetWindowSize(win, &width, &height);\n\n    /* OpenGL */\n    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);\n    glewExperimental = 1;\n    if (glewInit() != GLEW_OK) {\n        fprintf(stderr, \"Failed to setup GLEW\\n\");\n        exit(1);\n    }\n\n    /* GUI */\n    {device_init(&device);\n    {const void *image; int w, h;\n    struct nk_font *font;\n    nk_font_atlas_init_default(&atlas);\n    nk_font_atlas_begin(&atlas);\n    font = nk_font_atlas_add_default(&atlas, 13, 0);\n    image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    device_upload_atlas(&device, image, w, h);\n    nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.tex_null);\n    nk_init_default(&ctx, &font->handle);\n\n    glEnable(GL_TEXTURE_2D);\n    while (!glfwWindowShouldClose(win))\n    {\n        /* input */\n        pump_input(&ctx, win);\n\n        /* draw */\n        {struct nk_canvas canvas;\n        canvas_begin(&ctx, &canvas, 0, 0, 0, width, height, nk_rgb(250,250,250));\n        {\n            nk_fill_rect(canvas.painter, nk_rect(15,15,210,210), 5, nk_rgb(247, 230, 154));\n            nk_fill_rect(canvas.painter, nk_rect(20,20,200,200), 5, nk_rgb(188, 174, 118));\n            nk_draw_text(canvas.painter, nk_rect(30, 30, 150, 20), \"Text to draw\", 12, &font->handle, nk_rgb(188,174,118), nk_rgb(0,0,0));\n            nk_fill_rect(canvas.painter, nk_rect(250,20,100,100), 0, nk_rgb(0,0,255));\n            nk_fill_circle(canvas.painter, nk_rect(20,250,100,100), nk_rgb(255,0,0));\n            nk_fill_triangle(canvas.painter, 250, 250, 350, 250, 300, 350, nk_rgb(0,255,0));\n            nk_fill_arc(canvas.painter, 300, 180, 50, 0, 3.141592654f * 3.0f / 4.0f, nk_rgb(255,255,0));\n\n            {float points[12];\n            points[0] = 200; points[1] = 250;\n            points[2] = 250; points[3] = 350;\n            points[4] = 225; points[5] = 350;\n            points[6] = 200; points[7] = 300;\n            points[8] = 175; points[9] = 350;\n            points[10] = 150; points[11] = 350;\n            nk_fill_polygon(canvas.painter, points, 6, nk_rgb(0,0,0));}\n\n            nk_stroke_line(canvas.painter, 15, 10, 200, 10, 2.0f, nk_rgb(189,45,75));\n            nk_stroke_rect(canvas.painter, nk_rect(370, 20, 100, 100), 10, 3, nk_rgb(0,0,255));\n            nk_stroke_curve(canvas.painter, 380, 200, 405, 270, 455, 120, 480, 200, 2, nk_rgb(0,150,220));\n            nk_stroke_circle(canvas.painter, nk_rect(20, 370, 100, 100), 5, nk_rgb(0,255,120));\n            nk_stroke_triangle(canvas.painter, 370, 250, 470, 250, 420, 350, 6, nk_rgb(255,0,143));\n        }\n        canvas_end(&ctx, &canvas);}\n\n        /* Draw */\n        /* Framebuffer size is used instead of window size because the window size is in screen coordinates instead of pixels.\n         * See https://www.glfw.org/docs/latest/window_guide.html#window_size for more info\n         */\n        glfwGetFramebufferSize(win, &width, &height);\n        glViewport(0, 0, width, height);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(0.2f, 0.2f, 0.2f, 1.0f);\n        device_draw(&device, &ctx, width, height, NK_ANTI_ALIASING_ON);\n        glfwSwapBuffers(win);\n    }}}\n    nk_font_atlas_clear(&atlas);\n    nk_free(&ctx);\n    device_shutdown(&device);\n    glfwTerminate();\n    return 0;\n}\n\n"
  },
  {
    "path": "example/extended.c",
    "content": "/* nuklear - v1.05 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <time.h>\n#include <limits.h>\n\n#include <GL/glew.h>\n#include <GLFW/glfw3.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#include \"../nuklear.h\"\n\n#define STB_IMAGE_IMPLEMENTATION\n#include \"stb_image.h\"\n\n/* macros */\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define MAX_VERTEX_MEMORY 512 * 1024\n#define MAX_ELEMENT_MEMORY 128 * 1024\n\n#define UNUSED(a) (void)a\n#define MIN(a,b) ((a) < (b) ? (a) : (b))\n#define MAX(a,b) ((a) < (b) ? (b) : (a))\n#define LEN(a) (sizeof(a)/sizeof(a)[0])\n\n#ifdef __APPLE__\n  #define NK_SHADER_VERSION \"#version 150\\n\"\n#else\n  #define NK_SHADER_VERSION \"#version 300 es\\n\"\n#endif\n\nstruct media {\n    struct nk_font *font_14;\n    struct nk_font *font_18;\n    struct nk_font *font_20;\n    struct nk_font *font_22;\n\n    struct nk_image unchecked;\n    struct nk_image checked;\n    struct nk_image rocket;\n    struct nk_image cloud;\n    struct nk_image pen;\n    struct nk_image play;\n    struct nk_image pause;\n    struct nk_image stop;\n    struct nk_image prev;\n    struct nk_image next;\n    struct nk_image tools;\n    struct nk_image dir;\n    struct nk_image copy;\n    struct nk_image convert;\n    struct nk_image del;\n    struct nk_image edit;\n    struct nk_image images[9];\n    struct nk_image menu[6];\n};\n\n/* ===============================================================\n *\n *                          CUSTOM WIDGET\n *\n * ===============================================================*/\nstatic int\nui_piemenu(struct nk_context *ctx, struct nk_vec2 pos, float radius,\n            struct nk_image *icons, int item_count)\n{\n    int ret = -1;\n    struct nk_rect total_space;\n    struct nk_rect bounds;\n    int active_item = 0;\n\n    /* pie menu popup */\n    struct nk_color border = ctx->style.window.border_color;\n    struct nk_style_item background = ctx->style.window.fixed_background;\n    ctx->style.window.fixed_background = nk_style_item_hide();\n    ctx->style.window.border_color = nk_rgba(0,0,0,0);\n\n    total_space  = nk_window_get_content_region(ctx);\n    ctx->style.window.spacing = nk_vec2(0,0);\n    ctx->style.window.padding = nk_vec2(0,0);\n\n    if (nk_popup_begin(ctx, NK_POPUP_STATIC, \"piemenu\", NK_WINDOW_NO_SCROLLBAR,\n        nk_rect(pos.x - total_space.x - radius, pos.y - radius - total_space.y,\n        2*radius,2*radius)))\n    {\n        int i = 0;\n        struct nk_command_buffer* out = nk_window_get_canvas(ctx);\n        const struct nk_input *in = &ctx->input;\n\n        total_space = nk_window_get_content_region(ctx);\n        ctx->style.window.spacing = nk_vec2(4,4);\n        ctx->style.window.padding = nk_vec2(8,8);\n        nk_layout_row_dynamic(ctx, total_space.h, 1);\n        nk_widget(&bounds, ctx);\n\n        /* outer circle */\n        nk_fill_circle(out, bounds, nk_rgb(50,50,50));\n        {\n            /* circle buttons */\n            float step = (2 * 3.141592654f) / (float)(MAX(1,item_count));\n            float a_min = 0; float a_max = step;\n\n            struct nk_vec2 center = nk_vec2(bounds.x + bounds.w / 2.0f, bounds.y + bounds.h / 2.0f);\n            struct nk_vec2 drag = nk_vec2(in->mouse.pos.x - center.x, in->mouse.pos.y - center.y);\n            float angle = (float)atan2(drag.y, drag.x);\n            if (angle < -0.0f) angle += 2.0f * 3.141592654f;\n            active_item = (int)(angle/step);\n\n            for (i = 0; i < item_count; ++i) {\n                struct nk_rect content;\n                float rx, ry, dx, dy, a;\n                nk_fill_arc(out, center.x, center.y, (bounds.w/2.0f),\n                    a_min, a_max, (active_item == i) ? nk_rgb(45,100,255): nk_rgb(60,60,60));\n\n                /* separator line */\n                rx = bounds.w/2.0f; ry = 0;\n                dx = rx * (float)cos(a_min) - ry * (float)sin(a_min);\n                dy = rx * (float)sin(a_min) + ry * (float)cos(a_min);\n                nk_stroke_line(out, center.x, center.y,\n                    center.x + dx, center.y + dy, 1.0f, nk_rgb(50,50,50));\n\n                /* button content */\n                a = a_min + (a_max - a_min)/2.0f;\n                rx = bounds.w/2.5f; ry = 0;\n                content.w = 30; content.h = 30;\n                content.x = center.x + ((rx * (float)cos(a) - ry * (float)sin(a)) - content.w/2.0f);\n                content.y = center.y + (rx * (float)sin(a) + ry * (float)cos(a) - content.h/2.0f);\n                nk_draw_image(out, content, &icons[i], nk_rgb(255,255,255));\n                a_min = a_max; a_max += step;\n            }\n        }\n        {\n            /* inner circle */\n            struct nk_rect inner;\n            inner.x = bounds.x + bounds.w/2 - bounds.w/4;\n            inner.y = bounds.y + bounds.h/2 - bounds.h/4;\n            inner.w = bounds.w/2; inner.h = bounds.h/2;\n            nk_fill_circle(out, inner, nk_rgb(45,45,45));\n\n            /* active icon content */\n            bounds.w = inner.w / 2.0f;\n            bounds.h = inner.h / 2.0f;\n            bounds.x = inner.x + inner.w/2 - bounds.w/2;\n            bounds.y = inner.y + inner.h/2 - bounds.h/2;\n            nk_draw_image(out, bounds, &icons[active_item], nk_rgb(255,255,255));\n        }\n        nk_layout_space_end(ctx);\n        if (!nk_input_is_mouse_down(&ctx->input, NK_BUTTON_RIGHT)) {\n            nk_popup_close(ctx);\n            ret = active_item;\n        }\n    } else ret = -2;\n    ctx->style.window.spacing = nk_vec2(4,4);\n    ctx->style.window.padding = nk_vec2(8,8);\n    nk_popup_end(ctx);\n\n    ctx->style.window.fixed_background = background;\n    ctx->style.window.border_color = border;\n    return ret;\n}\n\n/* ===============================================================\n *\n *                          GRID\n *\n * ===============================================================*/\nstatic void\ngrid_demo(struct nk_context *ctx, struct media *media)\n{\n    static char text[3][64];\n    static int text_len[3];\n    static const char *items[] = {\"Item 0\",\"item 1\",\"item 2\"};\n    static int selected_item = 0;\n    static int check = 1;\n\n    int i;\n    nk_style_set_font(ctx, &media->font_20->handle);\n    if (nk_begin(ctx, \"Grid Demo\", nk_rect(600, 350, 275, 250),\n        NK_WINDOW_TITLE|NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|\n        NK_WINDOW_NO_SCROLLBAR))\n    {\n        nk_style_set_font(ctx, &media->font_18->handle);\n        nk_layout_row_dynamic(ctx, 30, 2);\n        nk_label(ctx, \"Floating point:\", NK_TEXT_RIGHT);\n        nk_edit_string(ctx, NK_EDIT_FIELD, text[0], &text_len[0], 64, nk_filter_float);\n        nk_label(ctx, \"Hexadecimal:\", NK_TEXT_RIGHT);\n        nk_edit_string(ctx, NK_EDIT_FIELD, text[1], &text_len[1], 64, nk_filter_hex);\n        nk_label(ctx, \"Binary:\", NK_TEXT_RIGHT);\n        nk_edit_string(ctx, NK_EDIT_FIELD, text[2], &text_len[2], 64, nk_filter_binary);\n        nk_label(ctx, \"Checkbox:\", NK_TEXT_RIGHT);\n        nk_checkbox_label(ctx, \"Check me\", &check);\n        nk_label(ctx, \"Combobox:\", NK_TEXT_RIGHT);\n        if (nk_combo_begin_label(ctx, items[selected_item], nk_vec2(nk_widget_width(ctx), 200))) {\n            nk_layout_row_dynamic(ctx, 25, 1);\n            for (i = 0; i < 3; ++i)\n                if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))\n                    selected_item = i;\n            nk_combo_end(ctx);\n        }\n    }\n    nk_end(ctx);\n    nk_style_set_font(ctx, &media->font_14->handle);\n}\n\n/* ===============================================================\n *\n *                          BUTTON DEMO\n *\n * ===============================================================*/\nstatic void\nui_header(struct nk_context *ctx, struct media *media, const char *title)\n{\n    nk_style_set_font(ctx, &media->font_18->handle);\n    nk_layout_row_dynamic(ctx, 20, 1);\n    nk_label(ctx, title, NK_TEXT_LEFT);\n}\n\nstatic void\nui_widget(struct nk_context *ctx, struct media *media, float height)\n{\n    static const float ratio[] = {0.15f, 0.85f};\n    nk_style_set_font(ctx, &media->font_22->handle);\n    nk_layout_row(ctx, NK_DYNAMIC, height, 2, ratio);\n    nk_spacing(ctx, 1);\n}\n\nstatic void\nui_widget_centered(struct nk_context *ctx, struct media *media, float height)\n{\n    static const float ratio[] = {0.15f, 0.50f, 0.35f};\n    nk_style_set_font(ctx, &media->font_22->handle);\n    nk_layout_row(ctx, NK_DYNAMIC, height, 3, ratio);\n    nk_spacing(ctx, 1);\n}\n\nstatic void\nbutton_demo(struct nk_context *ctx, struct media *media)\n{\n    static int option = 1;\n    static int toggle0 = 1;\n    static int toggle1 = 0;\n    static int toggle2 = 1;\n\n    nk_style_set_font(ctx, &media->font_20->handle);\n    nk_begin(ctx, \"Button Demo\", nk_rect(50,50,255,610),\n        NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_TITLE);\n\n    /*------------------------------------------------\n     *                  MENU\n     *------------------------------------------------*/\n    nk_menubar_begin(ctx);\n    {\n        /* toolbar */\n        nk_layout_row_static(ctx, 40, 40, 4);\n        if (nk_menu_begin_image(ctx, \"Music\", media->play, nk_vec2(110,120)))\n        {\n            /* settings */\n            nk_layout_row_dynamic(ctx, 25, 1);\n            nk_menu_item_image_label(ctx, media->play, \"Play\", NK_TEXT_RIGHT);\n            nk_menu_item_image_label(ctx, media->stop, \"Stop\", NK_TEXT_RIGHT);\n            nk_menu_item_image_label(ctx, media->pause, \"Pause\", NK_TEXT_RIGHT);\n            nk_menu_item_image_label(ctx, media->next, \"Next\", NK_TEXT_RIGHT);\n            nk_menu_item_image_label(ctx, media->prev, \"Prev\", NK_TEXT_RIGHT);\n            nk_menu_end(ctx);\n        }\n        nk_button_image(ctx, media->tools);\n        nk_button_image(ctx, media->cloud);\n        nk_button_image(ctx, media->pen);\n    }\n    nk_menubar_end(ctx);\n\n    /*------------------------------------------------\n     *                  BUTTON\n     *------------------------------------------------*/\n    ui_header(ctx, media, \"Push buttons\");\n    ui_widget(ctx, media, 35);\n    if (nk_button_label(ctx, \"Push me\"))\n        fprintf(stdout, \"pushed!\\n\");\n    ui_widget(ctx, media, 35);\n    if (nk_button_image_label(ctx, media->rocket, \"Styled\", NK_TEXT_CENTERED))\n        fprintf(stdout, \"rocket!\\n\");\n\n    /*------------------------------------------------\n     *                  REPEATER\n     *------------------------------------------------*/\n    ui_header(ctx, media, \"Repeater\");\n    ui_widget(ctx, media, 35);\n    if (nk_button_label(ctx, \"Press me\"))\n        fprintf(stdout, \"pressed!\\n\");\n\n    /*------------------------------------------------\n     *                  TOGGLE\n     *------------------------------------------------*/\n    ui_header(ctx, media, \"Toggle buttons\");\n    ui_widget(ctx, media, 35);\n    if (nk_button_image_label(ctx, (toggle0) ? media->checked: media->unchecked, \"Toggle\", NK_TEXT_LEFT))\n        toggle0 = !toggle0;\n\n    ui_widget(ctx, media, 35);\n    if (nk_button_image_label(ctx, (toggle1) ? media->checked: media->unchecked, \"Toggle\", NK_TEXT_LEFT))\n        toggle1 = !toggle1;\n\n    ui_widget(ctx, media, 35);\n    if (nk_button_image_label(ctx, (toggle2) ? media->checked: media->unchecked, \"Toggle\", NK_TEXT_LEFT))\n        toggle2 = !toggle2;\n\n    /*------------------------------------------------\n     *                  RADIO\n     *------------------------------------------------*/\n    ui_header(ctx, media, \"Radio buttons\");\n    ui_widget(ctx, media, 35);\n    if (nk_button_symbol_label(ctx, (option == 0)?NK_SYMBOL_CIRCLE_OUTLINE:NK_SYMBOL_CIRCLE_SOLID, \"Select\", NK_TEXT_LEFT))\n        option = 0;\n    ui_widget(ctx, media, 35);\n    if (nk_button_symbol_label(ctx, (option == 1)?NK_SYMBOL_CIRCLE_OUTLINE:NK_SYMBOL_CIRCLE_SOLID, \"Select\", NK_TEXT_LEFT))\n        option = 1;\n    ui_widget(ctx, media, 35);\n    if (nk_button_symbol_label(ctx, (option == 2)?NK_SYMBOL_CIRCLE_OUTLINE:NK_SYMBOL_CIRCLE_SOLID, \"Select\", NK_TEXT_LEFT))\n        option = 2;\n\n    /*------------------------------------------------\n     *                  CONTEXTUAL\n     *------------------------------------------------*/\n    nk_style_set_font(ctx, &media->font_18->handle);\n    if (nk_contextual_begin(ctx, NK_WINDOW_NO_SCROLLBAR, nk_vec2(150, 300), nk_window_get_bounds(ctx))) {\n        nk_layout_row_dynamic(ctx, 30, 1);\n        if (nk_contextual_item_image_label(ctx, media->copy, \"Clone\", NK_TEXT_RIGHT))\n            fprintf(stdout, \"pressed clone!\\n\");\n        if (nk_contextual_item_image_label(ctx, media->del, \"Delete\", NK_TEXT_RIGHT))\n            fprintf(stdout, \"pressed delete!\\n\");\n        if (nk_contextual_item_image_label(ctx, media->convert, \"Convert\", NK_TEXT_RIGHT))\n            fprintf(stdout, \"pressed convert!\\n\");\n        if (nk_contextual_item_image_label(ctx, media->edit, \"Edit\", NK_TEXT_RIGHT))\n            fprintf(stdout, \"pressed edit!\\n\");\n        nk_contextual_end(ctx);\n    }\n    nk_style_set_font(ctx, &media->font_14->handle);\n    nk_end(ctx);\n}\n\n/* ===============================================================\n *\n *                          BASIC DEMO\n *\n * ===============================================================*/\nstatic void\nbasic_demo(struct nk_context *ctx, struct media *media)\n{\n    static int image_active;\n    static int check0 = 1;\n    static int check1 = 0;\n    static size_t prog = 80;\n    static int selected_item = 0;\n    static int selected_image = 3;\n    static int selected_icon = 0;\n    static const char *items[] = {\"Item 0\",\"item 1\",\"item 2\"};\n    static int piemenu_active = 0;\n    static struct nk_vec2 piemenu_pos;\n\n    int i = 0;\n    nk_style_set_font(ctx, &media->font_20->handle);\n    nk_begin(ctx, \"Basic Demo\", nk_rect(320, 50, 275, 610),\n        NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_TITLE);\n\n    /*------------------------------------------------\n     *                  POPUP BUTTON\n     *------------------------------------------------*/\n    ui_header(ctx, media, \"Popup & Scrollbar & Images\");\n    ui_widget(ctx, media, 35);\n    if (nk_button_image_label(ctx, media->dir, \"Images\", NK_TEXT_CENTERED))\n        image_active = !image_active;\n\n    /*------------------------------------------------\n     *                  SELECTED IMAGE\n     *------------------------------------------------*/\n    ui_header(ctx, media, \"Selected Image\");\n    ui_widget_centered(ctx, media, 100);\n    nk_image(ctx, media->images[selected_image]);\n\n    /*------------------------------------------------\n     *                  IMAGE POPUP\n     *------------------------------------------------*/\n    if (image_active) {\n        if (nk_popup_begin(ctx, NK_POPUP_STATIC, \"Image Popup\", 0, nk_rect(265, 0, 320, 220))) {\n            nk_layout_row_static(ctx, 82, 82, 3);\n            for (i = 0; i < 9; ++i) {\n                if (nk_button_image(ctx, media->images[i])) {\n                    selected_image = i;\n                    image_active = 0;\n                    nk_popup_close(ctx);\n                }\n            }\n            nk_popup_end(ctx);\n        }\n    }\n    /*------------------------------------------------\n     *                  COMBOBOX\n     *------------------------------------------------*/\n    ui_header(ctx, media, \"Combo box\");\n    ui_widget(ctx, media, 40);\n    if (nk_combo_begin_label(ctx, items[selected_item], nk_vec2(nk_widget_width(ctx), 200))) {\n        nk_layout_row_dynamic(ctx, 35, 1);\n        for (i = 0; i < 3; ++i)\n            if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))\n                selected_item = i;\n        nk_combo_end(ctx);\n    }\n\n    ui_widget(ctx, media, 40);\n    if (nk_combo_begin_image_label(ctx, items[selected_icon], media->images[selected_icon], nk_vec2(nk_widget_width(ctx), 200))) {\n        nk_layout_row_dynamic(ctx, 35, 1);\n        for (i = 0; i < 3; ++i)\n            if (nk_combo_item_image_label(ctx, media->images[i], items[i], NK_TEXT_RIGHT))\n                selected_icon = i;\n        nk_combo_end(ctx);\n    }\n\n    /*------------------------------------------------\n     *                  CHECKBOX\n     *------------------------------------------------*/\n    ui_header(ctx, media, \"Checkbox\");\n    ui_widget(ctx, media, 30);\n    nk_checkbox_label(ctx, \"Flag 1\", &check0);\n    ui_widget(ctx, media, 30);\n    nk_checkbox_label(ctx, \"Flag 2\", &check1);\n\n    /*------------------------------------------------\n     *                  PROGRESSBAR\n     *------------------------------------------------*/\n    ui_header(ctx, media, \"Progressbar\");\n    ui_widget(ctx, media, 35);\n    nk_progress(ctx, &prog, 100, nk_true);\n\n    /*------------------------------------------------\n     *                  PIEMENU\n     *------------------------------------------------*/\n    if (nk_input_is_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_RIGHT,\n        nk_window_get_bounds(ctx),nk_true)){\n        piemenu_pos = ctx->input.mouse.pos;\n        piemenu_active = 1;\n    }\n\n    if (piemenu_active) {\n        int ret = ui_piemenu(ctx, piemenu_pos, 140, &media->menu[0], 6);\n        if (ret == -2) piemenu_active = 0;\n        if (ret != -1) {\n            fprintf(stdout, \"piemenu selected: %d\\n\", ret);\n            piemenu_active = 0;\n        }\n    }\n    nk_style_set_font(ctx, &media->font_14->handle);\n    nk_end(ctx);\n}\n\n/* ===============================================================\n *\n *                          DEVICE\n *\n * ===============================================================*/\nstruct nk_glfw_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstruct device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint vbo, vao, ebo;\n    GLuint prog;\n    GLuint vert_shdr;\n    GLuint frag_shdr;\n    GLint attrib_pos;\n    GLint attrib_uv;\n    GLint attrib_col;\n    GLint uniform_tex;\n    GLint uniform_proj;\n    GLuint font_tex;\n};\n\nstatic void\ndie(const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    fputs(\"\\n\", stderr);\n    exit(EXIT_FAILURE);\n}\n\nstatic struct nk_image\nicon_load(const char *filename)\n{\n    int x,y,n;\n    GLuint tex;\n    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);\n    if (!data) die(\"[SDL]: failed to load image: %s\", filename);\n\n    glGenTextures(1, &tex);\n    glBindTexture(GL_TEXTURE_2D, tex);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);\n    glGenerateMipmap(GL_TEXTURE_2D);\n    stbi_image_free(data);\n    return nk_image_id((int)tex);\n}\n\nstatic void\ndevice_init(struct device *dev)\n{\n    GLint status;\n    static const GLchar *vertex_shader =\n        NK_SHADER_VERSION\n        \"uniform mat4 ProjMtx;\\n\"\n        \"in vec2 Position;\\n\"\n        \"in vec2 TexCoord;\\n\"\n        \"in vec4 Color;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main() {\\n\"\n        \"   Frag_UV = TexCoord;\\n\"\n        \"   Frag_Color = Color;\\n\"\n        \"   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\\n\"\n        \"}\\n\";\n    static const GLchar *fragment_shader =\n        NK_SHADER_VERSION\n        \"precision mediump float;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"out vec4 Out_Color;\\n\"\n        \"void main(){\\n\"\n        \"   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    nk_buffer_init_default(&dev->cmds);\n    dev->prog = glCreateProgram();\n    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);\n    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);\n    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);\n    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);\n    glCompileShader(dev->vert_shdr);\n    glCompileShader(dev->frag_shdr);\n    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glAttachShader(dev->prog, dev->vert_shdr);\n    glAttachShader(dev->prog, dev->frag_shdr);\n    glLinkProgram(dev->prog);\n    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);\n    assert(status == GL_TRUE);\n\n    dev->uniform_tex = glGetUniformLocation(dev->prog, \"Texture\");\n    dev->uniform_proj = glGetUniformLocation(dev->prog, \"ProjMtx\");\n    dev->attrib_pos = glGetAttribLocation(dev->prog, \"Position\");\n    dev->attrib_uv = glGetAttribLocation(dev->prog, \"TexCoord\");\n    dev->attrib_col = glGetAttribLocation(dev->prog, \"Color\");\n\n    {\n        /* buffer setup */\n        GLsizei vs = sizeof(struct nk_glfw_vertex);\n        size_t vp = offsetof(struct nk_glfw_vertex, position);\n        size_t vt = offsetof(struct nk_glfw_vertex, uv);\n        size_t vc = offsetof(struct nk_glfw_vertex, col);\n\n        glGenBuffers(1, &dev->vbo);\n        glGenBuffers(1, &dev->ebo);\n        glGenVertexArrays(1, &dev->vao);\n\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glEnableVertexAttribArray((GLuint)dev->attrib_pos);\n        glEnableVertexAttribArray((GLuint)dev->attrib_uv);\n        glEnableVertexAttribArray((GLuint)dev->attrib_col);\n\n        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);\n        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);\n        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);\n    }\n\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n}\n\nstatic void\ndevice_upload_atlas(struct device *dev, const void *image, int width, int height)\n{\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nstatic void\ndevice_shutdown(struct device *dev)\n{\n    glDetachShader(dev->prog, dev->vert_shdr);\n    glDetachShader(dev->prog, dev->frag_shdr);\n    glDeleteShader(dev->vert_shdr);\n    glDeleteShader(dev->frag_shdr);\n    glDeleteProgram(dev->prog);\n    glDeleteTextures(1, &dev->font_tex);\n    glDeleteBuffers(1, &dev->vbo);\n    glDeleteBuffers(1, &dev->ebo);\n    nk_buffer_free(&dev->cmds);\n}\n\nstatic void\ndevice_draw(struct device *dev, struct nk_context *ctx, int width, int height,\n    struct nk_vec2 scale, enum nk_anti_aliasing AA)\n{\n    GLfloat ortho[4][4] = {\n        {2.0f, 0.0f, 0.0f, 0.0f},\n        {0.0f,-2.0f, 0.0f, 0.0f},\n        {0.0f, 0.0f,-1.0f, 0.0f},\n        {-1.0f,1.0f, 0.0f, 1.0f},\n    };\n    ortho[0][0] /= (GLfloat)width;\n    ortho[1][1] /= (GLfloat)height;\n\n    /* setup global state */\n    glEnable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glActiveTexture(GL_TEXTURE0);\n\n    /* setup program */\n    glUseProgram(dev->prog);\n    glUniform1i(dev->uniform_tex, 0);\n    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        void *vertices, *elements;\n        const nk_draw_index *offset = NULL;\n\n        /* allocate vertex and element buffer */\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);\n\n        /* load draw vertices & elements directly into vertex + element buffer */\n        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);\n        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n                {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},\n                {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},\n                {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},\n                {NK_VERTEX_LAYOUT_END}\n            };\n            NK_MEMSET(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_glfw_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            {struct nk_buffer vbuf, ebuf;\n            nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);\n            nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);\n            nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}\n        }\n        glUnmapBuffer(GL_ARRAY_BUFFER);\n        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);\n\n        /* iterate over and execute each draw command */\n        nk_draw_foreach(cmd, ctx, &dev->cmds)\n        {\n            if (!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor(\n                (GLint)(cmd->clip_rect.x * scale.x),\n                (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),\n                (GLint)(cmd->clip_rect.w * scale.x),\n                (GLint)(cmd->clip_rect.h * scale.y));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(ctx);\n        nk_buffer_clear(&dev->cmds);\n    }\n\n    /* default OpenGL state */\n    glUseProgram(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n    glDisable(GL_BLEND);\n    glDisable(GL_SCISSOR_TEST);\n}\n\n/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/\nstatic void error_callback(int e, const char *d){printf(\"Error %d: %s\\n\", e, d);}\nstatic void text_input(GLFWwindow *win, unsigned int codepoint)\n{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}\nstatic void scroll_input(GLFWwindow *win, double _, double yoff)\n{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));}\n\nint main(int argc, char *argv[])\n{\n    /* Platform */\n    static GLFWwindow *win;\n    int width = 0, height = 0;\n    int display_width=0, display_height=0;\n\n    /* GUI */\n    struct device device;\n    struct nk_font_atlas atlas;\n    struct media media;\n    struct nk_context ctx;\n\n    NK_UNUSED(argc);\n    NK_UNUSED(argv);\n\n    /* GLFW */\n    glfwSetErrorCallback(error_callback);\n    if (!glfwInit()) {\n        fprintf(stdout, \"[GFLW] failed to init!\\n\");\n        exit(1);\n    }\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);\n    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);\n#ifdef __APPLE__\n    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);\n#endif\n    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, \"Demo\", NULL, NULL);\n    glfwMakeContextCurrent(win);\n    glfwSetWindowUserPointer(win, &ctx);\n    glfwSetCharCallback(win, text_input);\n    glfwSetScrollCallback(win, scroll_input);\n    glfwGetWindowSize(win, &width, &height);\n    glfwGetFramebufferSize(win, &display_width, &display_height);\n\n    /* OpenGL */\n    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);\n    glewExperimental = 1;\n    if (glewInit() != GLEW_OK) {\n        fprintf(stderr, \"Failed to setup GLEW\\n\");\n        exit(1);\n    }\n\n    {/* GUI */\n    device_init(&device);\n    {const void *image; int w, h;\n    struct nk_font_config cfg = nk_font_config(0);\n    cfg.oversample_h = 3; cfg.oversample_v = 2;\n    /* Loading one font with different heights is only required if you want higher\n     * quality text otherwise you can just set the font height directly\n     * e.g.: ctx->style.font.height = 20. */\n    nk_font_atlas_init_default(&atlas);\n    nk_font_atlas_begin(&atlas);\n    media.font_14 = nk_font_atlas_add_from_file(&atlas, \"../../extra_font/Roboto-Regular.ttf\", 14.0f, &cfg);\n    media.font_18 = nk_font_atlas_add_from_file(&atlas, \"../../extra_font/Roboto-Regular.ttf\", 18.0f, &cfg);\n    media.font_20 = nk_font_atlas_add_from_file(&atlas, \"../../extra_font/Roboto-Regular.ttf\", 20.0f, &cfg);\n    media.font_22 = nk_font_atlas_add_from_file(&atlas, \"../../extra_font/Roboto-Regular.ttf\", 22.0f, &cfg);\n    image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    device_upload_atlas(&device, image, w, h);\n    nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.tex_null);}\n    nk_init_default(&ctx, &media.font_14->handle);}\n\n    /* icons */\n    glEnable(GL_TEXTURE_2D);\n    media.unchecked = icon_load(\"../icon/unchecked.png\");\n    media.checked = icon_load(\"../icon/checked.png\");\n    media.rocket = icon_load(\"../icon/rocket.png\");\n    media.cloud = icon_load(\"../icon/cloud.png\");\n    media.pen = icon_load(\"../icon/pen.png\");\n    media.play = icon_load(\"../icon/play.png\");\n    media.pause = icon_load(\"../icon/pause.png\");\n    media.stop = icon_load(\"../icon/stop.png\");\n    media.next =  icon_load(\"../icon/next.png\");\n    media.prev =  icon_load(\"../icon/prev.png\");\n    media.tools = icon_load(\"../icon/tools.png\");\n    media.dir = icon_load(\"../icon/directory.png\");\n    media.copy = icon_load(\"../icon/copy.png\");\n    media.convert = icon_load(\"../icon/export.png\");\n    media.del = icon_load(\"../icon/delete.png\");\n    media.edit = icon_load(\"../icon/edit.png\");\n    media.menu[0] = icon_load(\"../icon/home.png\");\n    media.menu[1] = icon_load(\"../icon/phone.png\");\n    media.menu[2] = icon_load(\"../icon/plane.png\");\n    media.menu[3] = icon_load(\"../icon/wifi.png\");\n    media.menu[4] = icon_load(\"../icon/settings.png\");\n    media.menu[5] = icon_load(\"../icon/volume.png\");\n\n    {int i;\n    for (i = 0; i < 9; ++i) {\n        char buffer[256];\n        sprintf(buffer, \"../images/image%d.png\", (i+1));\n        media.images[i] = icon_load(buffer);\n    }}\n\n    while (!glfwWindowShouldClose(win))\n    {\n        /* High DPI displays */\n        struct nk_vec2 scale;\n        glfwGetWindowSize(win, &width, &height);\n        glfwGetFramebufferSize(win, &display_width, &display_height);\n        scale.x = (float)display_width/(float)width;\n        scale.y = (float)display_height/(float)height;\n\n        /* Input */\n        {double x, y;\n        nk_input_begin(&ctx);\n        glfwPollEvents();\n        nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);\n        if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||\n            glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {\n            nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);\n            nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);\n            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);\n            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);\n            nk_input_key(&ctx, NK_KEY_SHIFT, 1);\n        } else {\n            nk_input_key(&ctx, NK_KEY_COPY, 0);\n            nk_input_key(&ctx, NK_KEY_PASTE, 0);\n            nk_input_key(&ctx, NK_KEY_CUT, 0);\n            nk_input_key(&ctx, NK_KEY_SHIFT, 0);\n        }\n        glfwGetCursorPos(win, &x, &y);\n        nk_input_motion(&ctx, (int)x, (int)y);\n        nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);\n        nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);\n        nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);\n        nk_input_end(&ctx);}\n\n        /* GUI */\n        basic_demo(&ctx, &media);\n        button_demo(&ctx, &media);\n        grid_demo(&ctx, &media);\n\n        /* Draw */\n        glViewport(0, 0, display_width, display_height);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(0.3f, 0.3f, 0.3f, 1.0f);\n        device_draw(&device, &ctx, width, height, scale, NK_ANTI_ALIASING_ON);\n        glfwSwapBuffers(win);\n    }\n\n    glDeleteTextures(1,(const GLuint*)&media.unchecked.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.checked.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.rocket.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.cloud.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.pen.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.play.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.pause.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.stop.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.next.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.prev.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.tools.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.dir.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.del.handle.id);\n\n    nk_font_atlas_clear(&atlas);\n    nk_free(&ctx);\n\n    device_shutdown(&device);\n    glfwTerminate();\n    return 0;\n}\n\n"
  },
  {
    "path": "example/file_browser.c",
    "content": "/* nuklear - v1.05 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <time.h>\n#include <limits.h>\n#include <unistd.h>\n#include <dirent.h>\n\n#include <GL/glew.h>\n#include <GLFW/glfw3.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#include \"../nuklear.h\"\n\n#define STB_IMAGE_IMPLEMENTATION\n#include \"stb_image.h\"\n\n/* macros */\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define MAX_VERTEX_MEMORY 512 * 1024\n#define MAX_ELEMENT_MEMORY 128 * 1024\n\n#define UNUSED(a) (void)a\n#define MIN(a,b) ((a) < (b) ? (a) : (b))\n#define MAX(a,b) ((a) < (b) ? (b) : (a))\n#define LEN(a) (sizeof(a)/sizeof(a)[0])\n\n#ifdef __APPLE__\n  #define NK_SHADER_VERSION \"#version 150\\n\"\n#else\n  #define NK_SHADER_VERSION \"#version 300 es\\n\"\n#endif\n\n/* ===============================================================\n *\n *                          GUI\n *\n * ===============================================================*/\nstruct icons {\n    struct nk_image desktop;\n    struct nk_image home;\n    struct nk_image computer;\n    struct nk_image directory;\n\n    struct nk_image default_file;\n    struct nk_image text_file;\n    struct nk_image music_file;\n    struct nk_image font_file;\n    struct nk_image img_file;\n    struct nk_image movie_file;\n};\n\nenum file_groups {\n    FILE_GROUP_DEFAULT,\n    FILE_GROUP_TEXT,\n    FILE_GROUP_MUSIC,\n    FILE_GROUP_FONT,\n    FILE_GROUP_IMAGE,\n    FILE_GROUP_MOVIE,\n    FILE_GROUP_MAX\n};\n\nenum file_types {\n    FILE_DEFAULT,\n    FILE_TEXT,\n    FILE_C_SOURCE,\n    FILE_CPP_SOURCE,\n    FILE_HEADER,\n    FILE_CPP_HEADER,\n    FILE_MP3,\n    FILE_WAV,\n    FILE_OGG,\n    FILE_TTF,\n    FILE_BMP,\n    FILE_PNG,\n    FILE_JPEG,\n    FILE_PCX,\n    FILE_TGA,\n    FILE_GIF,\n    FILE_MAX\n};\n\nstruct file_group {\n    enum file_groups group;\n    const char *name;\n    struct nk_image *icon;\n};\n\nstruct file {\n    enum file_types type;\n    const char *suffix;\n    enum file_groups group;\n};\n\nstruct media {\n    int font;\n    int icon_sheet;\n    struct icons icons;\n    struct file_group group[FILE_GROUP_MAX];\n    struct file files[FILE_MAX];\n};\n\n#define MAX_PATH_LEN 512\nstruct file_browser {\n    /* path */\n    char file[MAX_PATH_LEN];\n    char home[MAX_PATH_LEN];\n    char desktop[MAX_PATH_LEN];\n    char directory[MAX_PATH_LEN];\n\n    /* directory content */\n    char **files;\n    char **directories;\n    size_t file_count;\n    size_t dir_count;\n    struct media *media;\n};\n\n#ifdef __unix__\n#include <dirent.h>\n#include <unistd.h>\n#endif\n\n#ifndef _WIN32\n# include <pwd.h>\n#endif\n\nstatic void\ndie(const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    fputs(\"\\n\", stderr);\n    exit(EXIT_FAILURE);\n}\n\n#if 0\nstatic char*\nfile_load(const char* path, size_t* siz)\n{\n    char *buf;\n    FILE *fd = fopen(path, \"rb\");\n    if (!fd) die(\"Failed to open file: %s\\n\", path);\n    fseek(fd, 0, SEEK_END);\n    *siz = (size_t)ftell(fd);\n    fseek(fd, 0, SEEK_SET);\n    buf = (char*)calloc(*siz, 1);\n    fread(buf, *siz, 1, fd);\n    fclose(fd);\n    return buf;\n}\n#endif\n\nstatic char*\nstr_duplicate(const char *src)\n{\n    char *ret;\n    size_t len = strlen(src);\n    if (!len) return 0;\n    ret = (char*)malloc(len+1);\n    if (!ret) return 0;\n    memcpy(ret, src, len);\n    ret[len] = '\\0';\n    return ret;\n}\n\nstatic void\ndir_free_list(char **list, size_t size)\n{\n    size_t i;\n    for (i = 0; i < size; ++i)\n        free(list[i]);\n    free(list);\n}\n\nstatic char**\ndir_list(const char *dir, int return_subdirs, size_t *count)\n{\n    size_t n = 0;\n    char buffer[MAX_PATH_LEN];\n    char **results = NULL;\n    const DIR *none = NULL;\n    size_t capacity = 32;\n    size_t size;\n    DIR *z;\n\n    assert(dir);\n    assert(count);\n    strncpy(buffer, dir, MAX_PATH_LEN);\n    buffer[MAX_PATH_LEN - 1] = 0;\n    n = strlen(buffer);\n\n    if (n > 0 && (buffer[n-1] != '/'))\n        buffer[n++] = '/';\n\n    size = 0;\n\n    z = opendir(dir);\n    if (z != none) {\n        int nonempty = 1;\n        struct dirent *data = readdir(z);\n        nonempty = (data != NULL);\n        if (!nonempty) return NULL;\n\n        do {\n            DIR *y;\n            char *p;\n            int is_subdir;\n            if (data->d_name[0] == '.')\n                continue;\n\n            strncpy(buffer + n, data->d_name, MAX_PATH_LEN-n);\n            y = opendir(buffer);\n            is_subdir = (y != NULL);\n            if (y != NULL) closedir(y);\n\n            if ((return_subdirs && is_subdir) || (!is_subdir && !return_subdirs)){\n                if (!size) {\n                    results = (char**)calloc(sizeof(char*), capacity);\n                } else if (size >= capacity) {\n                    void *old = results;\n                    capacity = capacity * 2;\n                    results = (char**)realloc(results, capacity * sizeof(char*));\n                    assert(results);\n                    if (!results) free(old);\n                }\n                p = str_duplicate(data->d_name);\n                results[size++] = p;\n            }\n        } while ((data = readdir(z)) != NULL);\n    }\n\n    if (z) closedir(z);\n    *count = size;\n    return results;\n}\n\nstatic struct file_group\nFILE_GROUP(enum file_groups group, const char *name, struct nk_image *icon)\n{\n    struct file_group fg;\n    fg.group = group;\n    fg.name = name;\n    fg.icon = icon;\n    return fg;\n}\n\nstatic struct file\nFILE_DEF(enum file_types type, const char *suffix, enum file_groups group)\n{\n    struct file fd;\n    fd.type = type;\n    fd.suffix = suffix;\n    fd.group = group;\n    return fd;\n}\n\nstatic struct nk_image*\nmedia_icon_for_file(struct media *media, const char *file)\n{\n    int i = 0;\n    const char *s = file;\n    char suffix[4];\n    int found = 0;\n    memset(suffix, 0, sizeof(suffix));\n\n    /* extract suffix .xxx from file */\n    while (*s++ != '\\0') {\n        if (found && i < 3)\n            suffix[i++] = *s;\n\n        if (*s == '.') {\n            if (found){\n                found = 0;\n                break;\n            }\n            found = 1;\n        }\n    }\n\n    /* check for all file definition of all groups for fitting suffix*/\n    for (i = 0; i < FILE_MAX && found; ++i) {\n        struct file *d = &media->files[i];\n        {\n            const char *f = d->suffix;\n            s = suffix;\n            while (f && *f && *s && *s == *f) {\n                s++; f++;\n            }\n\n            /* found correct file definition so */\n            if (f && *s == '\\0' && *f == '\\0')\n                return media->group[d->group].icon;\n        }\n    }\n    return &media->icons.default_file;\n}\n\nstatic void\nmedia_init(struct media *media)\n{\n    /* file groups */\n    struct icons *icons = &media->icons;\n    media->group[FILE_GROUP_DEFAULT] = FILE_GROUP(FILE_GROUP_DEFAULT,\"default\",&icons->default_file);\n    media->group[FILE_GROUP_TEXT] = FILE_GROUP(FILE_GROUP_TEXT, \"textual\", &icons->text_file);\n    media->group[FILE_GROUP_MUSIC] = FILE_GROUP(FILE_GROUP_MUSIC, \"music\", &icons->music_file);\n    media->group[FILE_GROUP_FONT] = FILE_GROUP(FILE_GROUP_FONT, \"font\", &icons->font_file);\n    media->group[FILE_GROUP_IMAGE] = FILE_GROUP(FILE_GROUP_IMAGE, \"image\", &icons->img_file);\n    media->group[FILE_GROUP_MOVIE] = FILE_GROUP(FILE_GROUP_MOVIE, \"movie\", &icons->movie_file);\n\n    /* files */\n    media->files[FILE_DEFAULT] = FILE_DEF(FILE_DEFAULT, NULL, FILE_GROUP_DEFAULT);\n    media->files[FILE_TEXT] = FILE_DEF(FILE_TEXT, \"txt\", FILE_GROUP_TEXT);\n    media->files[FILE_C_SOURCE] = FILE_DEF(FILE_C_SOURCE, \"c\", FILE_GROUP_TEXT);\n    media->files[FILE_CPP_SOURCE] = FILE_DEF(FILE_CPP_SOURCE, \"cpp\", FILE_GROUP_TEXT);\n    media->files[FILE_HEADER] = FILE_DEF(FILE_HEADER, \"h\", FILE_GROUP_TEXT);\n    media->files[FILE_CPP_HEADER] = FILE_DEF(FILE_HEADER, \"hpp\", FILE_GROUP_TEXT);\n    media->files[FILE_MP3] = FILE_DEF(FILE_MP3, \"mp3\", FILE_GROUP_MUSIC);\n    media->files[FILE_WAV] = FILE_DEF(FILE_WAV, \"wav\", FILE_GROUP_MUSIC);\n    media->files[FILE_OGG] = FILE_DEF(FILE_OGG, \"ogg\", FILE_GROUP_MUSIC);\n    media->files[FILE_TTF] = FILE_DEF(FILE_TTF, \"ttf\", FILE_GROUP_FONT);\n    media->files[FILE_BMP] = FILE_DEF(FILE_BMP, \"bmp\", FILE_GROUP_IMAGE);\n    media->files[FILE_PNG] = FILE_DEF(FILE_PNG, \"png\", FILE_GROUP_IMAGE);\n    media->files[FILE_JPEG] = FILE_DEF(FILE_JPEG, \"jpg\", FILE_GROUP_IMAGE);\n    media->files[FILE_PCX] = FILE_DEF(FILE_PCX, \"pcx\", FILE_GROUP_IMAGE);\n    media->files[FILE_TGA] = FILE_DEF(FILE_TGA, \"tga\", FILE_GROUP_IMAGE);\n    media->files[FILE_GIF] = FILE_DEF(FILE_GIF, \"gif\", FILE_GROUP_IMAGE);\n}\n\nstatic void\nfile_browser_reload_directory_content(struct file_browser *browser, const char *path)\n{\n    const size_t path_len = nk_strlen(path) + 1;\n    NK_MEMCPY(browser->directory, path, MIN(path_len, MAX_PATH_LEN));\n    browser->directory[MAX_PATH_LEN - 1] = 0;\n    dir_free_list(browser->files, browser->file_count);\n    dir_free_list(browser->directories, browser->dir_count);\n    browser->files = dir_list(path, 0, &browser->file_count);\n    browser->directories = dir_list(path, 1, &browser->dir_count);\n}\n\nstatic void\nfile_browser_init(struct file_browser *browser, struct media *media)\n{\n    memset(browser, 0, sizeof(*browser));\n    browser->media = media;\n    {\n        /* load files and sub-directory list */\n        const char *home = getenv(\"HOME\");\n#ifdef _WIN32\n        if (!home) home = getenv(\"USERPROFILE\");\n#else\n        if (!home) home = getpwuid(getuid())->pw_dir;\n        {\n            size_t l;\n            strncpy(browser->home, home, MAX_PATH_LEN);\n            browser->home[MAX_PATH_LEN - 1] = 0;\n            l = strlen(browser->home);\n            strcpy(browser->home + l, \"/\");\n            strcpy(browser->directory, browser->home);\n        }\n#endif\n        {\n            size_t l;\n            strcpy(browser->desktop, browser->home);\n            l = strlen(browser->desktop);\n            strcpy(browser->desktop + l, \"desktop/\");\n        }\n        browser->files = dir_list(browser->directory, 0, &browser->file_count);\n        browser->directories = dir_list(browser->directory, 1, &browser->dir_count);\n    }\n}\n\nstatic void\nfile_browser_free(struct file_browser *browser)\n{\n    if (browser->files)\n        dir_free_list(browser->files, browser->file_count);\n    if (browser->directories)\n        dir_free_list(browser->directories, browser->dir_count);\n    browser->files = NULL;\n    browser->directories = NULL;\n    memset(browser, 0, sizeof(*browser));\n}\n\nstatic int\nfile_browser_run(struct file_browser *browser, struct nk_context *ctx)\n{\n    int ret = 0;\n    struct media *media = browser->media;\n    struct nk_rect total_space;\n\n    if (nk_begin(ctx, \"File Browser\", nk_rect(50, 50, 800, 600),\n        NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE))\n    {\n        static float ratio[] = {0.25f, NK_UNDEFINED};\n        float spacing_x = ctx->style.window.spacing.x;\n\n        /* output path directory selector in the menubar */\n        ctx->style.window.spacing.x = 0;\n        nk_menubar_begin(ctx);\n        {\n            char *d = browser->directory;\n            char *begin = d + 1;\n            nk_layout_row_dynamic(ctx, 25, 6);\n            while (*d++) {\n                if (*d == '/') {\n                    *d = '\\0';\n                    if (nk_button_label(ctx, begin)) {\n                        *d++ = '/'; *d = '\\0';\n                        file_browser_reload_directory_content(browser, browser->directory);\n                        break;\n                    }\n                    *d = '/';\n                    begin = d + 1;\n                }\n            }\n        }\n        nk_menubar_end(ctx);\n        ctx->style.window.spacing.x = spacing_x;\n\n        /* window layout */\n        total_space = nk_window_get_content_region(ctx);\n        nk_layout_row(ctx, NK_DYNAMIC, total_space.h, 2, ratio);\n        nk_group_begin(ctx, \"Special\", NK_WINDOW_NO_SCROLLBAR);\n        {\n            struct nk_image home = media->icons.home;\n            struct nk_image desktop = media->icons.desktop;\n            struct nk_image computer = media->icons.computer;\n\n            nk_layout_row_dynamic(ctx, 40, 1);\n            if (nk_button_image_label(ctx, home, \"home\", NK_TEXT_CENTERED))\n                file_browser_reload_directory_content(browser, browser->home);\n            if (nk_button_image_label(ctx,desktop,\"desktop\",NK_TEXT_CENTERED))\n                file_browser_reload_directory_content(browser, browser->desktop);\n            if (nk_button_image_label(ctx,computer,\"computer\",NK_TEXT_CENTERED))\n                file_browser_reload_directory_content(browser, \"/\");\n            nk_group_end(ctx);\n        }\n\n        /* output directory content window */\n        nk_group_begin(ctx, \"Content\", 0);\n        {\n            int index = -1;\n            size_t i = 0, j = 0, k = 0;\n            size_t rows = 0, cols = 0;\n            size_t count = browser->dir_count + browser->file_count;\n\n            cols = 4;\n            rows = count / cols;\n            for (i = 0; i <= rows; i += 1) {\n                {size_t n = j + cols;\n                nk_layout_row_dynamic(ctx, 135, (int)cols);\n                for (; j < count && j < n; ++j) {\n                    /* draw one row of icons */\n                    if (j < browser->dir_count) {\n                        /* draw and execute directory buttons */\n                        if (nk_button_image(ctx,media->icons.directory))\n                            index = (int)j;\n                    } else {\n                        /* draw and execute files buttons */\n                        struct nk_image *icon;\n                        size_t fileIndex = ((size_t)j - browser->dir_count);\n                        icon = media_icon_for_file(media,browser->files[fileIndex]);\n                        if (nk_button_image(ctx, *icon)) {\n                            strncpy(browser->file, browser->directory, MAX_PATH_LEN);\n                            n = strlen(browser->file);\n                            strncpy(browser->file + n, browser->files[fileIndex], MAX_PATH_LEN - n);\n                            ret = 1;\n                        }\n                    }\n                }}\n                {size_t n = k + cols;\n                nk_layout_row_dynamic(ctx, 20, (int)cols);\n                for (; k < count && k < n; k++) {\n                    /* draw one row of labels */\n                    if (k < browser->dir_count) {\n                        nk_label(ctx, browser->directories[k], NK_TEXT_CENTERED);\n                    } else {\n                        size_t t = k-browser->dir_count;\n                        nk_label(ctx,browser->files[t],NK_TEXT_CENTERED);\n                    }\n                }}\n            }\n\n            if (index != -1) {\n                size_t n = strlen(browser->directory);\n                strncpy(browser->directory + n, browser->directories[index], MAX_PATH_LEN - n);\n                n = strlen(browser->directory);\n                if (n < MAX_PATH_LEN - 1) {\n                    browser->directory[n] = '/';\n                    browser->directory[n+1] = '\\0';\n                }\n                file_browser_reload_directory_content(browser, browser->directory);\n            }\n            nk_group_end(ctx);\n        }\n    }\n    nk_end(ctx);\n    return ret;\n}\n\n/* ===============================================================\n *\n *                          DEVICE\n *\n * ===============================================================*/\nstruct nk_glfw_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstruct device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint vbo, vao, ebo;\n    GLuint prog;\n    GLuint vert_shdr;\n    GLuint frag_shdr;\n    GLint attrib_pos;\n    GLint attrib_uv;\n    GLint attrib_col;\n    GLint uniform_tex;\n    GLint uniform_proj;\n    GLuint font_tex;\n};\nstatic struct nk_image\nicon_load(const char *filename)\n{\n    int x,y,n;\n    GLuint tex;\n    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);\n    if (!data) die(\"[SDL]: failed to load image: %s\", filename);\n\n    glGenTextures(1, &tex);\n    glBindTexture(GL_TEXTURE_2D, tex);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);\n    glGenerateMipmap(GL_TEXTURE_2D);\n    stbi_image_free(data);\n    return nk_image_id((int)tex);\n}\n\nstatic void\ndevice_init(struct device *dev)\n{\n    GLint status;\n    static const GLchar *vertex_shader =\n        NK_SHADER_VERSION\n        \"uniform mat4 ProjMtx;\\n\"\n        \"in vec2 Position;\\n\"\n        \"in vec2 TexCoord;\\n\"\n        \"in vec4 Color;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main() {\\n\"\n        \"   Frag_UV = TexCoord;\\n\"\n        \"   Frag_Color = Color;\\n\"\n        \"   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\\n\"\n        \"}\\n\";\n    static const GLchar *fragment_shader =\n        NK_SHADER_VERSION\n        \"precision mediump float;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"out vec4 Out_Color;\\n\"\n        \"void main(){\\n\"\n        \"   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    nk_buffer_init_default(&dev->cmds);\n    dev->prog = glCreateProgram();\n    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);\n    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);\n    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);\n    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);\n    glCompileShader(dev->vert_shdr);\n    glCompileShader(dev->frag_shdr);\n    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glAttachShader(dev->prog, dev->vert_shdr);\n    glAttachShader(dev->prog, dev->frag_shdr);\n    glLinkProgram(dev->prog);\n    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);\n    assert(status == GL_TRUE);\n\n    dev->uniform_tex = glGetUniformLocation(dev->prog, \"Texture\");\n    dev->uniform_proj = glGetUniformLocation(dev->prog, \"ProjMtx\");\n    dev->attrib_pos = glGetAttribLocation(dev->prog, \"Position\");\n    dev->attrib_uv = glGetAttribLocation(dev->prog, \"TexCoord\");\n    dev->attrib_col = glGetAttribLocation(dev->prog, \"Color\");\n\n    {\n        /* buffer setup */\n        GLsizei vs = sizeof(struct nk_glfw_vertex);\n        size_t vp = offsetof(struct nk_glfw_vertex, position);\n        size_t vt = offsetof(struct nk_glfw_vertex, uv);\n        size_t vc = offsetof(struct nk_glfw_vertex, col);\n\n        glGenBuffers(1, &dev->vbo);\n        glGenBuffers(1, &dev->ebo);\n        glGenVertexArrays(1, &dev->vao);\n\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glEnableVertexAttribArray((GLuint)dev->attrib_pos);\n        glEnableVertexAttribArray((GLuint)dev->attrib_uv);\n        glEnableVertexAttribArray((GLuint)dev->attrib_col);\n\n        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);\n        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);\n        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);\n    }\n\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n}\n\nstatic void\ndevice_upload_atlas(struct device *dev, const void *image, int width, int height)\n{\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nstatic void\ndevice_shutdown(struct device *dev)\n{\n    glDetachShader(dev->prog, dev->vert_shdr);\n    glDetachShader(dev->prog, dev->frag_shdr);\n    glDeleteShader(dev->vert_shdr);\n    glDeleteShader(dev->frag_shdr);\n    glDeleteProgram(dev->prog);\n    glDeleteTextures(1, &dev->font_tex);\n    glDeleteBuffers(1, &dev->vbo);\n    glDeleteBuffers(1, &dev->ebo);\n    nk_buffer_free(&dev->cmds);\n}\n\nstatic void\ndevice_draw(struct device *dev, struct nk_context *ctx, int width, int height,\n    struct nk_vec2 scale, enum nk_anti_aliasing AA)\n{\n    GLfloat ortho[4][4] = {\n        {2.0f, 0.0f, 0.0f, 0.0f},\n        {0.0f,-2.0f, 0.0f, 0.0f},\n        {0.0f, 0.0f,-1.0f, 0.0f},\n        {-1.0f,1.0f, 0.0f, 1.0f},\n    };\n    ortho[0][0] /= (GLfloat)width;\n    ortho[1][1] /= (GLfloat)height;\n\n    /* setup global state */\n    glEnable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glActiveTexture(GL_TEXTURE0);\n\n    /* setup program */\n    glUseProgram(dev->prog);\n    glUniform1i(dev->uniform_tex, 0);\n    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        void *vertices, *elements;\n        const nk_draw_index *offset = NULL;\n\n        /* allocate vertex and element buffer */\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);\n\n        /* load draw vertices & elements directly into vertex + element buffer */\n        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);\n        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n                {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},\n                {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},\n                {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},\n                {NK_VERTEX_LAYOUT_END}\n            };\n            NK_MEMSET(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_glfw_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            {struct nk_buffer vbuf, ebuf;\n            nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);\n            nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);\n            nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}\n        }\n        glUnmapBuffer(GL_ARRAY_BUFFER);\n        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);\n\n        /* iterate over and execute each draw command */\n        nk_draw_foreach(cmd, ctx, &dev->cmds) {\n            if (!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor(\n                (GLint)(cmd->clip_rect.x * scale.x),\n                (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),\n                (GLint)(cmd->clip_rect.w * scale.x),\n                (GLint)(cmd->clip_rect.h * scale.y));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(ctx);\n        nk_buffer_clear(&dev->cmds);\n    }\n\n    /* default OpenGL state */\n    glUseProgram(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n    glDisable(GL_BLEND);\n    glDisable(GL_SCISSOR_TEST);\n}\n\n\n/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/\nstatic void error_callback(int e, const char *d){printf(\"Error %d: %s\\n\", e, d);}\nstatic void text_input(GLFWwindow *win, unsigned int codepoint)\n{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}\nstatic void scroll_input(GLFWwindow *win, double _, double yoff)\n{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));}\n\nint main(int argc, char *argv[])\n{\n    /* Platform */\n    static GLFWwindow *win;\n    int width = 0, height = 0;\n    int display_width = 0, display_height = 0;\n\n    /* GUI */\n    struct device device;\n    struct nk_context ctx;\n    struct nk_font *font;\n    struct nk_font_atlas atlas;\n    struct file_browser browser;\n    struct media media;\n\n    /* GLFW */\n    glfwSetErrorCallback(error_callback);\n    if (!glfwInit()) {\n        fprintf(stdout, \"[GFLW] failed to init!\\n\");\n        exit(1);\n    }\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);\n    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);\n#ifdef __APPLE__\n    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);\n#endif\n    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, \"Demo\", NULL, NULL);\n    glfwMakeContextCurrent(win);\n    glfwSetWindowUserPointer(win, &ctx);\n    glfwSetCharCallback(win, text_input);\n    glfwSetScrollCallback(win, scroll_input);\n\n    /* OpenGL */\n    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);\n    glewExperimental = 1;\n    if (glewInit() != GLEW_OK) {\n        fprintf(stderr, \"Failed to setup GLEW\\n\");\n        exit(1);\n    }\n\n    {/* GUI */\n    device_init(&device);\n    {const void *image; int w, h;\n    const char *font_path = (argc > 1) ? argv[1]: 0;\n    nk_font_atlas_init_default(&atlas);\n    nk_font_atlas_begin(&atlas);\n    if (font_path) font = nk_font_atlas_add_from_file(&atlas, font_path, 13.0f, NULL);\n    else font = nk_font_atlas_add_default(&atlas, 13.0f, NULL);\n    image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    device_upload_atlas(&device, image, w, h);\n    nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.tex_null);}\n    nk_init_default(&ctx, &font->handle);}\n\n    /* icons */\n    glEnable(GL_TEXTURE_2D);\n    media.icons.home = icon_load(\"../icon/home.png\");\n    media.icons.directory = icon_load(\"../icon/directory.png\");\n    media.icons.computer = icon_load(\"../icon/computer.png\");\n    media.icons.desktop = icon_load(\"../icon/desktop.png\");\n    media.icons.default_file = icon_load(\"../icon/default.png\");\n    media.icons.text_file = icon_load(\"../icon/text.png\");\n    media.icons.music_file = icon_load(\"../icon/music.png\");\n    media.icons.font_file =  icon_load(\"../icon/font.png\");\n    media.icons.img_file = icon_load(\"../icon/img.png\");\n    media.icons.movie_file = icon_load(\"../icon/movie.png\");\n    media_init(&media);\n\n    file_browser_init(&browser, &media);\n    while (!glfwWindowShouldClose(win))\n    {\n        /* High DPI displays */\n        struct nk_vec2 scale;\n        glfwGetWindowSize(win, &width, &height);\n        glfwGetFramebufferSize(win, &display_width, &display_height);\n        scale.x = (float)display_width/(float)width;\n        scale.y = (float)display_height/(float)height;\n\n        /* Input */\n        {double x, y;\n        nk_input_begin(&ctx);\n        glfwPollEvents();\n        nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);\n        if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||\n            glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {\n            nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);\n            nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);\n            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);\n            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);\n            nk_input_key(&ctx, NK_KEY_SHIFT, 1);\n        } else {\n            nk_input_key(&ctx, NK_KEY_COPY, 0);\n            nk_input_key(&ctx, NK_KEY_PASTE, 0);\n            nk_input_key(&ctx, NK_KEY_CUT, 0);\n            nk_input_key(&ctx, NK_KEY_SHIFT, 0);\n        }\n        glfwGetCursorPos(win, &x, &y);\n        nk_input_motion(&ctx, (int)x, (int)y);\n        nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);\n        nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);\n        nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);\n        nk_input_end(&ctx);}\n\n        /* GUI */\n        file_browser_run(&browser, &ctx);\n\n        /* Draw */\n        glViewport(0, 0, display_width, display_height);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(0.2f, 0.2f, 0.2f, 1.0f);\n        device_draw(&device, &ctx, width, height, scale, NK_ANTI_ALIASING_ON);\n        glfwSwapBuffers(win);\n    }\n\n    glDeleteTextures(1,(const GLuint*)&media.icons.home.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.directory.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.computer.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.desktop.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.default_file.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.text_file.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.music_file.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.font_file.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.img_file.handle.id);\n    glDeleteTextures(1,(const GLuint*)&media.icons.movie_file.handle.id);\n\n    file_browser_free(&browser);\n    nk_font_atlas_clear(&atlas);\n    nk_free(&ctx);\n    device_shutdown(&device);\n    glfwTerminate();\n    return 0;\n}\n\n\n"
  },
  {
    "path": "example/skinning.c",
    "content": "/* nuklear - v1.05 - public domain */\n#include <stdio.h>\n#include <stdlib.h>\n#include <stdint.h>\n#include <stdarg.h>\n#include <string.h>\n#include <math.h>\n#include <assert.h>\n#include <time.h>\n#include <limits.h>\n\n#include <GL/glew.h>\n#include <GLFW/glfw3.h>\n\n#define NK_INCLUDE_FIXED_TYPES\n#define NK_INCLUDE_STANDARD_IO\n#define NK_INCLUDE_DEFAULT_ALLOCATOR\n#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n#define NK_INCLUDE_FONT_BAKING\n#define NK_INCLUDE_DEFAULT_FONT\n#define NK_IMPLEMENTATION\n#include \"../nuklear.h\"\n\n#define STB_IMAGE_IMPLEMENTATION\n#include \"stb_image.h\"\n\n/* macros */\n#define WINDOW_WIDTH 1200\n#define WINDOW_HEIGHT 800\n\n#define MAX_VERTEX_MEMORY 512 * 1024\n#define MAX_ELEMENT_MEMORY 128 * 1024\n\n#define UNUSED(a) (void)a\n#define MIN(a,b) ((a) < (b) ? (a) : (b))\n#define MAX(a,b) ((a) < (b) ? (b) : (a))\n#define LEN(a) (sizeof(a)/sizeof(a)[0])\n\n#ifdef __APPLE__\n  #define NK_SHADER_VERSION \"#version 150\\n\"\n#else\n  #define NK_SHADER_VERSION \"#version 300 es\\n\"\n#endif\n\nstruct media {\n    GLint skin;\n    struct nk_image menu;\n    struct nk_image check;\n    struct nk_image check_cursor;\n    struct nk_image option;\n    struct nk_image option_cursor;\n    struct nk_image header;\n    struct nk_image window;\n    struct nk_image scrollbar_inc_button;\n    struct nk_image scrollbar_inc_button_hover;\n    struct nk_image scrollbar_dec_button;\n    struct nk_image scrollbar_dec_button_hover;\n    struct nk_image button;\n    struct nk_image button_hover;\n    struct nk_image button_active;\n    struct nk_image tab_minimize;\n    struct nk_image tab_maximize;\n    struct nk_image slider;\n    struct nk_image slider_hover;\n    struct nk_image slider_active;\n};\n\n\n/* ===============================================================\n *\n *                          DEVICE\n *\n * ===============================================================*/\nstruct nk_glfw_vertex {\n    float position[2];\n    float uv[2];\n    nk_byte col[4];\n};\n\nstruct device {\n    struct nk_buffer cmds;\n    struct nk_draw_null_texture tex_null;\n    GLuint vbo, vao, ebo;\n    GLuint prog;\n    GLuint vert_shdr;\n    GLuint frag_shdr;\n    GLint attrib_pos;\n    GLint attrib_uv;\n    GLint attrib_col;\n    GLint uniform_tex;\n    GLint uniform_proj;\n    GLuint font_tex;\n};\n\nstatic void\ndie(const char *fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    vfprintf(stderr, fmt, ap);\n    va_end(ap);\n    fputs(\"\\n\", stderr);\n    exit(EXIT_FAILURE);\n}\n\nstatic GLuint\nimage_load(const char *filename)\n{\n    int x,y,n;\n    GLuint tex;\n    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);\n    if (!data) die(\"failed to load image: %s\", filename);\n\n    glGenTextures(1, &tex);\n    glBindTexture(GL_TEXTURE_2D, tex);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_NEAREST);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);\n    glGenerateMipmap(GL_TEXTURE_2D);\n    stbi_image_free(data);\n    return tex;\n}\n\nstatic void\ndevice_init(struct device *dev)\n{\n    GLint status;\n    static const GLchar *vertex_shader =\n        NK_SHADER_VERSION\n        \"uniform mat4 ProjMtx;\\n\"\n        \"in vec2 Position;\\n\"\n        \"in vec2 TexCoord;\\n\"\n        \"in vec4 Color;\\n\"\n        \"out vec2 Frag_UV;\\n\"\n        \"out vec4 Frag_Color;\\n\"\n        \"void main() {\\n\"\n        \"   Frag_UV = TexCoord;\\n\"\n        \"   Frag_Color = Color;\\n\"\n        \"   gl_Position = ProjMtx * vec4(Position.xy, 0, 1);\\n\"\n        \"}\\n\";\n    static const GLchar *fragment_shader =\n        NK_SHADER_VERSION\n        \"precision mediump float;\\n\"\n        \"uniform sampler2D Texture;\\n\"\n        \"in vec2 Frag_UV;\\n\"\n        \"in vec4 Frag_Color;\\n\"\n        \"out vec4 Out_Color;\\n\"\n        \"void main(){\\n\"\n        \"   Out_Color = Frag_Color * texture(Texture, Frag_UV.st);\\n\"\n        \"}\\n\";\n\n    nk_buffer_init_default(&dev->cmds);\n    dev->prog = glCreateProgram();\n    dev->vert_shdr = glCreateShader(GL_VERTEX_SHADER);\n    dev->frag_shdr = glCreateShader(GL_FRAGMENT_SHADER);\n    glShaderSource(dev->vert_shdr, 1, &vertex_shader, 0);\n    glShaderSource(dev->frag_shdr, 1, &fragment_shader, 0);\n    glCompileShader(dev->vert_shdr);\n    glCompileShader(dev->frag_shdr);\n    glGetShaderiv(dev->vert_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glGetShaderiv(dev->frag_shdr, GL_COMPILE_STATUS, &status);\n    assert(status == GL_TRUE);\n    glAttachShader(dev->prog, dev->vert_shdr);\n    glAttachShader(dev->prog, dev->frag_shdr);\n    glLinkProgram(dev->prog);\n    glGetProgramiv(dev->prog, GL_LINK_STATUS, &status);\n    assert(status == GL_TRUE);\n\n    dev->uniform_tex = glGetUniformLocation(dev->prog, \"Texture\");\n    dev->uniform_proj = glGetUniformLocation(dev->prog, \"ProjMtx\");\n    dev->attrib_pos = glGetAttribLocation(dev->prog, \"Position\");\n    dev->attrib_uv = glGetAttribLocation(dev->prog, \"TexCoord\");\n    dev->attrib_col = glGetAttribLocation(dev->prog, \"Color\");\n\n    {\n        /* buffer setup */\n        GLsizei vs = sizeof(struct nk_glfw_vertex);\n        size_t vp = offsetof(struct nk_glfw_vertex, position);\n        size_t vt = offsetof(struct nk_glfw_vertex, uv);\n        size_t vc = offsetof(struct nk_glfw_vertex, col);\n\n        glGenBuffers(1, &dev->vbo);\n        glGenBuffers(1, &dev->ebo);\n        glGenVertexArrays(1, &dev->vao);\n\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glEnableVertexAttribArray((GLuint)dev->attrib_pos);\n        glEnableVertexAttribArray((GLuint)dev->attrib_uv);\n        glEnableVertexAttribArray((GLuint)dev->attrib_col);\n\n        glVertexAttribPointer((GLuint)dev->attrib_pos, 2, GL_FLOAT, GL_FALSE, vs, (void*)vp);\n        glVertexAttribPointer((GLuint)dev->attrib_uv, 2, GL_FLOAT, GL_FALSE, vs, (void*)vt);\n        glVertexAttribPointer((GLuint)dev->attrib_col, 4, GL_UNSIGNED_BYTE, GL_TRUE, vs, (void*)vc);\n    }\n\n    glBindTexture(GL_TEXTURE_2D, 0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n}\n\nstatic void\ndevice_upload_atlas(struct device *dev, const void *image, int width, int height)\n{\n    glGenTextures(1, &dev->font_tex);\n    glBindTexture(GL_TEXTURE_2D, dev->font_tex);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0,\n                GL_RGBA, GL_UNSIGNED_BYTE, image);\n}\n\nstatic void\ndevice_shutdown(struct device *dev)\n{\n    glDetachShader(dev->prog, dev->vert_shdr);\n    glDetachShader(dev->prog, dev->frag_shdr);\n    glDeleteShader(dev->vert_shdr);\n    glDeleteShader(dev->frag_shdr);\n    glDeleteProgram(dev->prog);\n    glDeleteTextures(1, &dev->font_tex);\n    glDeleteBuffers(1, &dev->vbo);\n    glDeleteBuffers(1, &dev->ebo);\n    nk_buffer_free(&dev->cmds);\n}\n\nstatic void\ndevice_draw(struct device *dev, struct nk_context *ctx, int width, int height,\n    struct nk_vec2 scale, enum nk_anti_aliasing AA)\n{\n    GLfloat ortho[4][4] = {\n        {2.0f, 0.0f, 0.0f, 0.0f},\n        {0.0f,-2.0f, 0.0f, 0.0f},\n        {0.0f, 0.0f,-1.0f, 0.0f},\n        {-1.0f,1.0f, 0.0f, 1.0f},\n    };\n    ortho[0][0] /= (GLfloat)width;\n    ortho[1][1] /= (GLfloat)height;\n\n    /* setup global state */\n    glEnable(GL_BLEND);\n    glBlendEquation(GL_FUNC_ADD);\n    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glDisable(GL_CULL_FACE);\n    glDisable(GL_DEPTH_TEST);\n    glEnable(GL_SCISSOR_TEST);\n    glActiveTexture(GL_TEXTURE0);\n\n    /* setup program */\n    glUseProgram(dev->prog);\n    glUniform1i(dev->uniform_tex, 0);\n    glUniformMatrix4fv(dev->uniform_proj, 1, GL_FALSE, &ortho[0][0]);\n    {\n        /* convert from command queue into draw list and draw to screen */\n        const struct nk_draw_command *cmd;\n        void *vertices, *elements;\n        const nk_draw_index *offset = NULL;\n\n        /* allocate vertex and element buffer */\n        glBindVertexArray(dev->vao);\n        glBindBuffer(GL_ARRAY_BUFFER, dev->vbo);\n        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo);\n\n        glBufferData(GL_ARRAY_BUFFER, MAX_VERTEX_MEMORY, NULL, GL_STREAM_DRAW);\n        glBufferData(GL_ELEMENT_ARRAY_BUFFER, MAX_ELEMENT_MEMORY, NULL, GL_STREAM_DRAW);\n\n        /* load draw vertices & elements directly into vertex + element buffer */\n        vertices = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);\n        elements = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY);\n        {\n            /* fill convert configuration */\n            struct nk_convert_config config;\n            static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n                {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, position)},\n                {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct nk_glfw_vertex, uv)},\n                {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct nk_glfw_vertex, col)},\n                {NK_VERTEX_LAYOUT_END}\n            };\n            NK_MEMSET(&config, 0, sizeof(config));\n            config.vertex_layout = vertex_layout;\n            config.vertex_size = sizeof(struct nk_glfw_vertex);\n            config.vertex_alignment = NK_ALIGNOF(struct nk_glfw_vertex);\n            config.tex_null = dev->tex_null;\n            config.circle_segment_count = 22;\n            config.curve_segment_count = 22;\n            config.arc_segment_count = 22;\n            config.global_alpha = 1.0f;\n            config.shape_AA = AA;\n            config.line_AA = AA;\n\n            /* setup buffers to load vertices and elements */\n            {struct nk_buffer vbuf, ebuf;\n            nk_buffer_init_fixed(&vbuf, vertices, MAX_VERTEX_MEMORY);\n            nk_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY);\n            nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);}\n        }\n        glUnmapBuffer(GL_ARRAY_BUFFER);\n        glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);\n\n        /* iterate over and execute each draw command */\n        nk_draw_foreach(cmd, ctx, &dev->cmds)\n        {\n            if (!cmd->elem_count) continue;\n            glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);\n            glScissor(\n                (GLint)(cmd->clip_rect.x * scale.x),\n                (GLint)((height - (GLint)(cmd->clip_rect.y + cmd->clip_rect.h)) * scale.y),\n                (GLint)(cmd->clip_rect.w * scale.x),\n                (GLint)(cmd->clip_rect.h * scale.y));\n            glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);\n            offset += cmd->elem_count;\n        }\n        nk_clear(ctx);\n        nk_buffer_clear(&dev->cmds);\n    }\n\n    /* default OpenGL state */\n    glUseProgram(0);\n    glBindBuffer(GL_ARRAY_BUFFER, 0);\n    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);\n    glBindVertexArray(0);\n    glDisable(GL_BLEND);\n    glDisable(GL_SCISSOR_TEST);\n}\n\n/* glfw callbacks (I don't know if there is a easier way to access text and scroll )*/\nstatic void error_callback(int e, const char *d){printf(\"Error %d: %s\\n\", e, d);}\nstatic void text_input(GLFWwindow *win, unsigned int codepoint)\n{nk_input_unicode((struct nk_context*)glfwGetWindowUserPointer(win), codepoint);}\nstatic void scroll_input(GLFWwindow *win, double _, double yoff)\n{UNUSED(_);nk_input_scroll((struct nk_context*)glfwGetWindowUserPointer(win), nk_vec2(0, (float)yoff));}\n\nint main(int argc, char *argv[])\n{\n    /* Platform */\n    static GLFWwindow *win;\n    int width = 0, height = 0;\n    int display_width=0, display_height=0;\n\n    /* GUI */\n    struct device device;\n    struct nk_font_atlas atlas;\n    struct media media;\n    struct nk_context ctx;\n    struct nk_font *font;\n\n    /* GLFW */\n    glfwSetErrorCallback(error_callback);\n    if (!glfwInit()) {\n        fprintf(stdout, \"[GFLW] failed to init!\\n\");\n        exit(1);\n    }\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);\n    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);\n    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);\n#ifdef __APPLE__\n    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);\n#endif\n    win = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, \"Demo\", NULL, NULL);\n    glfwMakeContextCurrent(win);\n    glfwSetWindowUserPointer(win, &ctx);\n    glfwSetCharCallback(win, text_input);\n    glfwSetScrollCallback(win, scroll_input);\n    glfwGetWindowSize(win, &width, &height);\n    glfwGetFramebufferSize(win, &display_width, &display_height);\n\n    /* OpenGL */\n    glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);\n    glewExperimental = 1;\n    if (glewInit() != GLEW_OK) {\n        fprintf(stderr, \"Failed to setup GLEW\\n\");\n        exit(1);\n    }\n\n    /* GUI */\n    {device_init(&device);\n    {const void *image; int w, h;\n    const char *font_path = (argc > 1) ? argv[1]: 0;\n    nk_font_atlas_init_default(&atlas);\n    nk_font_atlas_begin(&atlas);\n    if (font_path) font = nk_font_atlas_add_from_file(&atlas, font_path, 13.0f, NULL);\n    else font = nk_font_atlas_add_default(&atlas, 13.0f, NULL);\n    image = nk_font_atlas_bake(&atlas, &w, &h, NK_FONT_ATLAS_RGBA32);\n    device_upload_atlas(&device, image, w, h);\n    nk_font_atlas_end(&atlas, nk_handle_id((int)device.font_tex), &device.tex_null);}\n    nk_init_default(&ctx, &font->handle);}\n\n    {   /* skin */\n        glEnable(GL_TEXTURE_2D);\n        media.skin = image_load(\"../skins/gwen.png\");\n        media.check = nk_subimage_id(media.skin, 512,512, nk_rect(464,32,15,15));\n        media.check_cursor = nk_subimage_id(media.skin, 512,512, nk_rect(450,34,11,11));\n        media.option = nk_subimage_id(media.skin, 512,512, nk_rect(464,64,15,15));\n        media.option_cursor = nk_subimage_id(media.skin, 512,512, nk_rect(451,67,9,9));\n        media.header = nk_subimage_id(media.skin, 512,512, nk_rect(128,0,127,24));\n        media.window = nk_subimage_id(media.skin, 512,512, nk_rect(128,23,127,104));\n        media.scrollbar_inc_button = nk_subimage_id(media.skin, 512,512, nk_rect(464,256,15,15));\n        media.scrollbar_inc_button_hover = nk_subimage_id(media.skin, 512,512, nk_rect(464,320,15,15));\n        media.scrollbar_dec_button = nk_subimage_id(media.skin, 512,512, nk_rect(464,224,15,15));\n        media.scrollbar_dec_button_hover = nk_subimage_id(media.skin, 512,512, nk_rect(464,288,15,15));\n        media.button = nk_subimage_id(media.skin, 512,512, nk_rect(384,336,127,31));\n        media.button_hover = nk_subimage_id(media.skin, 512,512, nk_rect(384,368,127,31));\n        media.button_active = nk_subimage_id(media.skin, 512,512, nk_rect(384,400,127,31));\n        media.tab_minimize = nk_subimage_id(media.skin, 512,512, nk_rect(451, 99, 9, 9));\n        media.tab_maximize = nk_subimage_id(media.skin, 512,512, nk_rect(467,99,9,9));\n        media.slider = nk_subimage_id(media.skin, 512,512, nk_rect(418,33,11,14));\n        media.slider_hover = nk_subimage_id(media.skin, 512,512, nk_rect(418,49,11,14));\n        media.slider_active = nk_subimage_id(media.skin, 512,512, nk_rect(418,64,11,14));\n\n        /* window */\n        ctx.style.window.background = nk_rgb(204,204,204);\n        ctx.style.window.fixed_background = nk_style_item_image(media.window);\n        ctx.style.window.border_color = nk_rgb(67,67,67);\n        ctx.style.window.combo_border_color = nk_rgb(67,67,67);\n        ctx.style.window.contextual_border_color = nk_rgb(67,67,67);\n        ctx.style.window.menu_border_color = nk_rgb(67,67,67);\n        ctx.style.window.group_border_color = nk_rgb(67,67,67);\n        ctx.style.window.tooltip_border_color = nk_rgb(67,67,67);\n        ctx.style.window.scrollbar_size = nk_vec2(16,16);\n        ctx.style.window.border_color = nk_rgba(0,0,0,0);\n        ctx.style.window.padding = nk_vec2(8,4);\n        ctx.style.window.border = 3;\n\n        /* window header */\n        ctx.style.window.header.normal = nk_style_item_image(media.header);\n        ctx.style.window.header.hover = nk_style_item_image(media.header);\n        ctx.style.window.header.active = nk_style_item_image(media.header);\n        ctx.style.window.header.label_normal = nk_rgb(95,95,95);\n        ctx.style.window.header.label_hover = nk_rgb(95,95,95);\n        ctx.style.window.header.label_active = nk_rgb(95,95,95);\n\n        /* scrollbar */\n        ctx.style.scrollv.normal          = nk_style_item_color(nk_rgb(184,184,184));\n        ctx.style.scrollv.hover           = nk_style_item_color(nk_rgb(184,184,184));\n        ctx.style.scrollv.active          = nk_style_item_color(nk_rgb(184,184,184));\n        ctx.style.scrollv.cursor_normal   = nk_style_item_color(nk_rgb(220,220,220));\n        ctx.style.scrollv.cursor_hover    = nk_style_item_color(nk_rgb(235,235,235));\n        ctx.style.scrollv.cursor_active   = nk_style_item_color(nk_rgb(99,202,255));\n        ctx.style.scrollv.dec_symbol      = NK_SYMBOL_NONE;\n        ctx.style.scrollv.inc_symbol      = NK_SYMBOL_NONE;\n        ctx.style.scrollv.show_buttons    = nk_true;\n        ctx.style.scrollv.border_color    = nk_rgb(81,81,81);\n        ctx.style.scrollv.cursor_border_color = nk_rgb(81,81,81);\n        ctx.style.scrollv.border          = 1;\n        ctx.style.scrollv.rounding        = 0;\n        ctx.style.scrollv.border_cursor   = 1;\n        ctx.style.scrollv.rounding_cursor = 2;\n\n        /* scrollbar buttons */\n        ctx.style.scrollv.inc_button.normal          = nk_style_item_image(media.scrollbar_inc_button);\n        ctx.style.scrollv.inc_button.hover           = nk_style_item_image(media.scrollbar_inc_button_hover);\n        ctx.style.scrollv.inc_button.active          = nk_style_item_image(media.scrollbar_inc_button_hover);\n        ctx.style.scrollv.inc_button.border_color    = nk_rgba(0,0,0,0);\n        ctx.style.scrollv.inc_button.text_background = nk_rgba(0,0,0,0);\n        ctx.style.scrollv.inc_button.text_normal     = nk_rgba(0,0,0,0);\n        ctx.style.scrollv.inc_button.text_hover      = nk_rgba(0,0,0,0);\n        ctx.style.scrollv.inc_button.text_active     = nk_rgba(0,0,0,0);\n        ctx.style.scrollv.inc_button.border          = 0.0f;\n\n        ctx.style.scrollv.dec_button.normal          = nk_style_item_image(media.scrollbar_dec_button);\n        ctx.style.scrollv.dec_button.hover           = nk_style_item_image(media.scrollbar_dec_button_hover);\n        ctx.style.scrollv.dec_button.active          = nk_style_item_image(media.scrollbar_dec_button_hover);\n        ctx.style.scrollv.dec_button.border_color    = nk_rgba(0,0,0,0);\n        ctx.style.scrollv.dec_button.text_background = nk_rgba(0,0,0,0);\n        ctx.style.scrollv.dec_button.text_normal     = nk_rgba(0,0,0,0);\n        ctx.style.scrollv.dec_button.text_hover      = nk_rgba(0,0,0,0);\n        ctx.style.scrollv.dec_button.text_active     = nk_rgba(0,0,0,0);\n        ctx.style.scrollv.dec_button.border          = 0.0f;\n\n        /* checkbox toggle */\n        {struct nk_style_toggle *toggle;\n        toggle = &ctx.style.checkbox;\n        toggle->normal          = nk_style_item_image(media.check);\n        toggle->hover           = nk_style_item_image(media.check);\n        toggle->active          = nk_style_item_image(media.check);\n        toggle->cursor_normal   = nk_style_item_image(media.check_cursor);\n        toggle->cursor_hover    = nk_style_item_image(media.check_cursor);\n        toggle->text_normal     = nk_rgb(95,95,95);\n        toggle->text_hover      = nk_rgb(95,95,95);\n        toggle->text_active     = nk_rgb(95,95,95);}\n\n        /* option toggle */\n        {struct nk_style_toggle *toggle;\n        toggle = &ctx.style.option;\n        toggle->normal          = nk_style_item_image(media.option);\n        toggle->hover           = nk_style_item_image(media.option);\n        toggle->active          = nk_style_item_image(media.option);\n        toggle->cursor_normal   = nk_style_item_image(media.option_cursor);\n        toggle->cursor_hover    = nk_style_item_image(media.option_cursor);\n        toggle->text_normal     = nk_rgb(95,95,95);\n        toggle->text_hover      = nk_rgb(95,95,95);\n        toggle->text_active     = nk_rgb(95,95,95);}\n\n        /* default button */\n        ctx.style.button.normal = nk_style_item_image(media.button);\n        ctx.style.button.hover = nk_style_item_image(media.button_hover);\n        ctx.style.button.active = nk_style_item_image(media.button_active);\n        ctx.style.button.border_color = nk_rgba(0,0,0,0);\n        ctx.style.button.text_background = nk_rgba(0,0,0,0);\n        ctx.style.button.text_normal = nk_rgb(95,95,95);\n        ctx.style.button.text_hover = nk_rgb(95,95,95);\n        ctx.style.button.text_active = nk_rgb(95,95,95);\n\n        /* default text */\n        ctx.style.text.color = nk_rgb(95,95,95);\n\n        /* contextual button */\n        ctx.style.contextual_button.normal = nk_style_item_color(nk_rgb(206,206,206));\n        ctx.style.contextual_button.hover = nk_style_item_color(nk_rgb(229,229,229));\n        ctx.style.contextual_button.active = nk_style_item_color(nk_rgb(99,202,255));\n        ctx.style.contextual_button.border_color = nk_rgba(0,0,0,0);\n        ctx.style.contextual_button.text_background = nk_rgba(0,0,0,0);\n        ctx.style.contextual_button.text_normal = nk_rgb(95,95,95);\n        ctx.style.contextual_button.text_hover = nk_rgb(95,95,95);\n        ctx.style.contextual_button.text_active = nk_rgb(95,95,95);\n\n        /* menu button */\n        ctx.style.menu_button.normal = nk_style_item_color(nk_rgb(206,206,206));\n        ctx.style.menu_button.hover = nk_style_item_color(nk_rgb(229,229,229));\n        ctx.style.menu_button.active = nk_style_item_color(nk_rgb(99,202,255));\n        ctx.style.menu_button.border_color = nk_rgba(0,0,0,0);\n        ctx.style.menu_button.text_background = nk_rgba(0,0,0,0);\n        ctx.style.menu_button.text_normal = nk_rgb(95,95,95);\n        ctx.style.menu_button.text_hover = nk_rgb(95,95,95);\n        ctx.style.menu_button.text_active = nk_rgb(95,95,95);\n\n        /* tree */\n        ctx.style.tab.text = nk_rgb(95,95,95);\n        ctx.style.tab.tab_minimize_button.normal = nk_style_item_image(media.tab_minimize);\n        ctx.style.tab.tab_minimize_button.hover = nk_style_item_image(media.tab_minimize);\n        ctx.style.tab.tab_minimize_button.active = nk_style_item_image(media.tab_minimize);\n        ctx.style.tab.tab_minimize_button.text_background = nk_rgba(0,0,0,0);\n        ctx.style.tab.tab_minimize_button.text_normal = nk_rgba(0,0,0,0);\n        ctx.style.tab.tab_minimize_button.text_hover = nk_rgba(0,0,0,0);\n        ctx.style.tab.tab_minimize_button.text_active = nk_rgba(0,0,0,0);\n\n        ctx.style.tab.tab_maximize_button.normal = nk_style_item_image(media.tab_maximize);\n        ctx.style.tab.tab_maximize_button.hover = nk_style_item_image(media.tab_maximize);\n        ctx.style.tab.tab_maximize_button.active = nk_style_item_image(media.tab_maximize);\n        ctx.style.tab.tab_maximize_button.text_background = nk_rgba(0,0,0,0);\n        ctx.style.tab.tab_maximize_button.text_normal = nk_rgba(0,0,0,0);\n        ctx.style.tab.tab_maximize_button.text_hover = nk_rgba(0,0,0,0);\n        ctx.style.tab.tab_maximize_button.text_active = nk_rgba(0,0,0,0);\n\n        ctx.style.tab.node_minimize_button.normal = nk_style_item_image(media.tab_minimize);\n        ctx.style.tab.node_minimize_button.hover = nk_style_item_image(media.tab_minimize);\n        ctx.style.tab.node_minimize_button.active = nk_style_item_image(media.tab_minimize);\n        ctx.style.tab.node_minimize_button.text_background = nk_rgba(0,0,0,0);\n        ctx.style.tab.node_minimize_button.text_normal = nk_rgba(0,0,0,0);\n        ctx.style.tab.node_minimize_button.text_hover = nk_rgba(0,0,0,0);\n        ctx.style.tab.node_minimize_button.text_active = nk_rgba(0,0,0,0);\n\n        ctx.style.tab.node_maximize_button.normal = nk_style_item_image(media.tab_maximize);\n        ctx.style.tab.node_maximize_button.hover = nk_style_item_image(media.tab_maximize);\n        ctx.style.tab.node_maximize_button.active = nk_style_item_image(media.tab_maximize);\n        ctx.style.tab.node_maximize_button.text_background = nk_rgba(0,0,0,0);\n        ctx.style.tab.node_maximize_button.text_normal = nk_rgba(0,0,0,0);\n        ctx.style.tab.node_maximize_button.text_hover = nk_rgba(0,0,0,0);\n        ctx.style.tab.node_maximize_button.text_active = nk_rgba(0,0,0,0);\n\n        /* selectable */\n        ctx.style.selectable.normal = nk_style_item_color(nk_rgb(206,206,206));\n        ctx.style.selectable.hover = nk_style_item_color(nk_rgb(206,206,206));\n        ctx.style.selectable.pressed = nk_style_item_color(nk_rgb(206,206,206));\n        ctx.style.selectable.normal_active = nk_style_item_color(nk_rgb(185,205,248));\n        ctx.style.selectable.hover_active = nk_style_item_color(nk_rgb(185,205,248));\n        ctx.style.selectable.pressed_active = nk_style_item_color(nk_rgb(185,205,248));\n        ctx.style.selectable.text_normal = nk_rgb(95,95,95);\n        ctx.style.selectable.text_hover = nk_rgb(95,95,95);\n        ctx.style.selectable.text_pressed = nk_rgb(95,95,95);\n        ctx.style.selectable.text_normal_active = nk_rgb(95,95,95);\n        ctx.style.selectable.text_hover_active = nk_rgb(95,95,95);\n        ctx.style.selectable.text_pressed_active = nk_rgb(95,95,95);\n\n        /* slider */\n        ctx.style.slider.normal          = nk_style_item_hide();\n        ctx.style.slider.hover           = nk_style_item_hide();\n        ctx.style.slider.active          = nk_style_item_hide();\n        ctx.style.slider.bar_normal      = nk_rgb(156,156,156);\n        ctx.style.slider.bar_hover       = nk_rgb(156,156,156);\n        ctx.style.slider.bar_active      = nk_rgb(156,156,156);\n        ctx.style.slider.bar_filled      = nk_rgb(156,156,156);\n        ctx.style.slider.cursor_normal   = nk_style_item_image(media.slider);\n        ctx.style.slider.cursor_hover    = nk_style_item_image(media.slider_hover);\n        ctx.style.slider.cursor_active   = nk_style_item_image(media.slider_active);\n        ctx.style.slider.cursor_size     = nk_vec2(16.5f,21);\n        ctx.style.slider.bar_height      = 1;\n\n        /* progressbar */\n        ctx.style.progress.normal = nk_style_item_color(nk_rgb(231,231,231));\n        ctx.style.progress.hover = nk_style_item_color(nk_rgb(231,231,231));\n        ctx.style.progress.active = nk_style_item_color(nk_rgb(231,231,231));\n        ctx.style.progress.cursor_normal = nk_style_item_color(nk_rgb(63,242,93));\n        ctx.style.progress.cursor_hover = nk_style_item_color(nk_rgb(63,242,93));\n        ctx.style.progress.cursor_active = nk_style_item_color(nk_rgb(63,242,93));\n        ctx.style.progress.border_color = nk_rgb(114,116,115);\n        ctx.style.progress.padding = nk_vec2(0,0);\n        ctx.style.progress.border = 2;\n        ctx.style.progress.rounding = 1;\n\n        /* combo */\n        ctx.style.combo.normal = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.combo.hover = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.combo.active = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.combo.border_color = nk_rgb(95,95,95);\n        ctx.style.combo.label_normal = nk_rgb(95,95,95);\n        ctx.style.combo.label_hover = nk_rgb(95,95,95);\n        ctx.style.combo.label_active = nk_rgb(95,95,95);\n        ctx.style.combo.border = 1;\n        ctx.style.combo.rounding = 1;\n\n        /* combo button */\n        ctx.style.combo.button.normal = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.combo.button.hover = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.combo.button.active = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.combo.button.text_background = nk_rgb(216,216,216);\n        ctx.style.combo.button.text_normal = nk_rgb(95,95,95);\n        ctx.style.combo.button.text_hover = nk_rgb(95,95,95);\n        ctx.style.combo.button.text_active = nk_rgb(95,95,95);\n\n        /* property */\n        ctx.style.property.normal = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.property.hover = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.property.active = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.property.border_color = nk_rgb(81,81,81);\n        ctx.style.property.label_normal = nk_rgb(95,95,95);\n        ctx.style.property.label_hover = nk_rgb(95,95,95);\n        ctx.style.property.label_active = nk_rgb(95,95,95);\n        ctx.style.property.sym_left = NK_SYMBOL_TRIANGLE_LEFT;\n        ctx.style.property.sym_right = NK_SYMBOL_TRIANGLE_RIGHT;\n        ctx.style.property.rounding = 10;\n        ctx.style.property.border = 1;\n\n        /* edit */\n        ctx.style.edit.normal = nk_style_item_color(nk_rgb(240,240,240));\n        ctx.style.edit.hover = nk_style_item_color(nk_rgb(240,240,240));\n        ctx.style.edit.active = nk_style_item_color(nk_rgb(240,240,240));\n        ctx.style.edit.border_color = nk_rgb(62,62,62);\n        ctx.style.edit.cursor_normal = nk_rgb(99,202,255);\n        ctx.style.edit.cursor_hover = nk_rgb(99,202,255);\n        ctx.style.edit.cursor_text_normal = nk_rgb(95,95,95);\n        ctx.style.edit.cursor_text_hover = nk_rgb(95,95,95);\n        ctx.style.edit.text_normal = nk_rgb(95,95,95);\n        ctx.style.edit.text_hover = nk_rgb(95,95,95);\n        ctx.style.edit.text_active = nk_rgb(95,95,95);\n        ctx.style.edit.selected_normal = nk_rgb(99,202,255);\n        ctx.style.edit.selected_hover = nk_rgb(99,202,255);\n        ctx.style.edit.selected_text_normal = nk_rgb(95,95,95);\n        ctx.style.edit.selected_text_hover = nk_rgb(95,95,95);\n        ctx.style.edit.border = 1;\n        ctx.style.edit.rounding = 2;\n\n        /* property buttons */\n        ctx.style.property.dec_button.normal = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.property.dec_button.hover = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.property.dec_button.active = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.property.dec_button.text_background = nk_rgba(0,0,0,0);\n        ctx.style.property.dec_button.text_normal = nk_rgb(95,95,95);\n        ctx.style.property.dec_button.text_hover = nk_rgb(95,95,95);\n        ctx.style.property.dec_button.text_active = nk_rgb(95,95,95);\n        ctx.style.property.inc_button = ctx.style.property.dec_button;\n\n        /* property edit */\n        ctx.style.property.edit.normal = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.property.edit.hover = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.property.edit.active = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.property.edit.border_color = nk_rgba(0,0,0,0);\n        ctx.style.property.edit.cursor_normal = nk_rgb(95,95,95);\n        ctx.style.property.edit.cursor_hover = nk_rgb(95,95,95);\n        ctx.style.property.edit.cursor_text_normal = nk_rgb(216,216,216);\n        ctx.style.property.edit.cursor_text_hover = nk_rgb(216,216,216);\n        ctx.style.property.edit.text_normal = nk_rgb(95,95,95);\n        ctx.style.property.edit.text_hover = nk_rgb(95,95,95);\n        ctx.style.property.edit.text_active = nk_rgb(95,95,95);\n        ctx.style.property.edit.selected_normal = nk_rgb(95,95,95);\n        ctx.style.property.edit.selected_hover = nk_rgb(95,95,95);\n        ctx.style.property.edit.selected_text_normal = nk_rgb(216,216,216);\n        ctx.style.property.edit.selected_text_hover = nk_rgb(216,216,216);\n\n        /* chart */\n        ctx.style.chart.background = nk_style_item_color(nk_rgb(216,216,216));\n        ctx.style.chart.border_color = nk_rgb(81,81,81);\n        ctx.style.chart.color = nk_rgb(95,95,95);\n        ctx.style.chart.selected_color = nk_rgb(255,0,0);\n        ctx.style.chart.border = 1;\n    }\n\n    while (!glfwWindowShouldClose(win))\n    {\n        /* High DPI displays */\n        struct nk_vec2 scale;\n        glfwGetWindowSize(win, &width, &height);\n        glfwGetFramebufferSize(win, &display_width, &display_height);\n        scale.x = (float)display_width/(float)width;\n        scale.y = (float)display_height/(float)height;\n\n        /* Input */\n        {double x, y;\n        nk_input_begin(&ctx);\n        glfwPollEvents();\n        nk_input_key(&ctx, NK_KEY_DEL, glfwGetKey(win, GLFW_KEY_DELETE) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_ENTER, glfwGetKey(win, GLFW_KEY_ENTER) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_TAB, glfwGetKey(win, GLFW_KEY_TAB) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_BACKSPACE, glfwGetKey(win, GLFW_KEY_BACKSPACE) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_LEFT, glfwGetKey(win, GLFW_KEY_LEFT) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_RIGHT, glfwGetKey(win, GLFW_KEY_RIGHT) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_UP, glfwGetKey(win, GLFW_KEY_UP) == GLFW_PRESS);\n        nk_input_key(&ctx, NK_KEY_DOWN, glfwGetKey(win, GLFW_KEY_DOWN) == GLFW_PRESS);\n        if (glfwGetKey(win, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS ||\n            glfwGetKey(win, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS) {\n            nk_input_key(&ctx, NK_KEY_COPY, glfwGetKey(win, GLFW_KEY_C) == GLFW_PRESS);\n            nk_input_key(&ctx, NK_KEY_PASTE, glfwGetKey(win, GLFW_KEY_P) == GLFW_PRESS);\n            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_X) == GLFW_PRESS);\n            nk_input_key(&ctx, NK_KEY_CUT, glfwGetKey(win, GLFW_KEY_E) == GLFW_PRESS);\n            nk_input_key(&ctx, NK_KEY_SHIFT, 1);\n        } else {\n            nk_input_key(&ctx, NK_KEY_COPY, 0);\n            nk_input_key(&ctx, NK_KEY_PASTE, 0);\n            nk_input_key(&ctx, NK_KEY_CUT, 0);\n            nk_input_key(&ctx, NK_KEY_SHIFT, 0);\n        }\n        glfwGetCursorPos(win, &x, &y);\n        nk_input_motion(&ctx, (int)x, (int)y);\n        nk_input_button(&ctx, NK_BUTTON_LEFT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS);\n        nk_input_button(&ctx, NK_BUTTON_MIDDLE, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_MIDDLE) == GLFW_PRESS);\n        nk_input_button(&ctx, NK_BUTTON_RIGHT, (int)x, (int)y, glfwGetMouseButton(win, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS);\n        nk_input_end(&ctx);}\n\n        /* GUI */\n        if (nk_begin(&ctx, \"Demo\", nk_rect(50, 50, 300, 400),\n            NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_TITLE))\n        {\n            int i;\n            float id;\n            static int slider = 10;\n            static int field_len;\n            static nk_size prog_value = 60;\n            static int current_weapon = 0;\n            static char field_buffer[64];\n            static float pos;\n            static const char *weapons[] = {\"Fist\",\"Pistol\",\"Shotgun\",\"Plasma\",\"BFG\"};\n            const float step = (2*3.141592654f) / 32;\n\n            nk_layout_row_static(&ctx, 30, 120, 1);\n            if (nk_button_label(&ctx, \"button\"))\n                fprintf(stdout, \"button pressed\\n\");\n\n            nk_layout_row_dynamic(&ctx, 20, 1);\n            nk_label(&ctx, \"Label\", NK_TEXT_LEFT);\n            nk_layout_row_dynamic(&ctx, 30, 2);\n            nk_check_label(&ctx, \"inactive\", 0);\n            nk_check_label(&ctx, \"active\", 1);\n            nk_option_label(&ctx, \"active\", 1);\n            nk_option_label(&ctx, \"inactive\", 0);\n\n            nk_layout_row_dynamic(&ctx, 30, 1);\n            nk_slider_int(&ctx, 0, &slider, 16, 1);\n            nk_layout_row_dynamic(&ctx, 20, 1);\n            nk_progress(&ctx, &prog_value, 100, NK_MODIFIABLE);\n\n            nk_layout_row_dynamic(&ctx, 25, 1);\n            nk_edit_string(&ctx, NK_EDIT_FIELD, field_buffer, &field_len, 64, nk_filter_default);\n            nk_property_float(&ctx, \"#X:\", -1024.0f, &pos, 1024.0f, 1, 1);\n            current_weapon = nk_combo(&ctx, weapons, LEN(weapons), current_weapon, 25, nk_vec2(nk_widget_width(&ctx),200));\n\n            nk_layout_row_dynamic(&ctx, 100, 1);\n            if (nk_chart_begin_colored(&ctx, NK_CHART_LINES, nk_rgb(255,0,0), nk_rgb(150,0,0), 32, 0.0f, 1.0f)) {\n                nk_chart_add_slot_colored(&ctx, NK_CHART_LINES, nk_rgb(0,0,255), nk_rgb(0,0,150),32, -1.0f, 1.0f);\n                nk_chart_add_slot_colored(&ctx, NK_CHART_LINES, nk_rgb(0,255,0), nk_rgb(0,150,0), 32, -1.0f, 1.0f);\n                for (id = 0, i = 0; i < 32; ++i) {\n                    nk_chart_push_slot(&ctx, (float)fabs(sin(id)), 0);\n                    nk_chart_push_slot(&ctx, (float)cos(id), 1);\n                    nk_chart_push_slot(&ctx, (float)sin(id), 2);\n                    id += step;\n                }\n            }\n            nk_chart_end(&ctx);\n\n            nk_layout_row_dynamic(&ctx, 250, 1);\n            if (nk_group_begin(&ctx, \"Standard\", NK_WINDOW_BORDER|NK_WINDOW_BORDER))\n            {\n                if (nk_tree_push(&ctx, NK_TREE_NODE, \"Window\", NK_MAXIMIZED)) {\n                    static int selected[8];\n                    if (nk_tree_push(&ctx, NK_TREE_NODE, \"Next\", NK_MAXIMIZED)) {\n                        nk_layout_row_dynamic(&ctx, 20, 1);\n                        for (i = 0; i < 4; ++i)\n                            nk_selectable_label(&ctx, (selected[i]) ? \"Selected\": \"Unselected\", NK_TEXT_LEFT, &selected[i]);\n                        nk_tree_pop(&ctx);\n                    }\n                    if (nk_tree_push(&ctx, NK_TREE_NODE, \"Previous\", NK_MAXIMIZED)) {\n                        nk_layout_row_dynamic(&ctx, 20, 1);\n                        for (i = 4; i < 8; ++i)\n                            nk_selectable_label(&ctx, (selected[i]) ? \"Selected\": \"Unselected\", NK_TEXT_LEFT, &selected[i]);\n                        nk_tree_pop(&ctx);\n                    }\n                    nk_tree_pop(&ctx);\n                }\n                nk_group_end(&ctx);\n            }\n        }\n        nk_end(&ctx);\n\n        /* Draw */\n        glViewport(0, 0, display_width, display_height);\n        glClear(GL_COLOR_BUFFER_BIT);\n        glClearColor(0.5882, 0.6666, 0.6666, 1.0f);\n        device_draw(&device, &ctx, width, height, scale, NK_ANTI_ALIASING_ON);\n        glfwSwapBuffers(win);\n    }\n    glDeleteTextures(1,(const GLuint*)&media.skin);\n    nk_font_atlas_clear(&atlas);\n    nk_free(&ctx);\n    device_shutdown(&device);\n    glfwTerminate();\n    return 0;\n}\n\n"
  },
  {
    "path": "example/stb_image.h",
    "content": "/* stb_image - v2.08 - public domain image loader - http://nothings.org/stb_image.h\n                                     no warranty implied; use at your own risk\n\n   Do this:\n      #define STB_IMAGE_IMPLEMENTATION\n   before you include this file in *one* C or C++ file to create the implementation.\n\n   // i.e. it should look like this:\n   #include ...\n   #include ...\n   #include ...\n   #define STB_IMAGE_IMPLEMENTATION\n   #include \"stb_image.h\"\n\n   You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.\n   And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free\n\n\n   QUICK NOTES:\n      Primarily of interest to game developers and other people who can\n          avoid problematic images and only need the trivial interface\n\n      JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)\n      PNG 1/2/4/8-bit-per-channel (16 bpc not supported)\n\n      TGA (not sure what subset, if a subset)\n      BMP non-1bpp, non-RLE\n      PSD (composited view only, no extra channels, 8/16 bit-per-channel)\n\n      GIF (*comp always reports as 4-channel)\n      HDR (radiance rgbE format)\n      PIC (Softimage PIC)\n      PNM (PPM and PGM binary only)\n\n      Animated GIF still needs a proper API, but here's one way to do it:\n          http://gist.github.com/urraka/685d9a6340b26b830d49\n\n      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)\n      - decode from arbitrary I/O callbacks\n      - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)\n\n   Full documentation under \"DOCUMENTATION\" below.\n\n\n   Revision 2.00 release notes:\n\n      - Progressive JPEG is now supported.\n\n      - PPM and PGM binary formats are now supported, thanks to Ken Miller.\n\n      - x86 platforms now make use of SSE2 SIMD instructions for\n        JPEG decoding, and ARM platforms can use NEON SIMD if requested.\n        This work was done by Fabian \"ryg\" Giesen. SSE2 is used by\n        default, but NEON must be enabled explicitly; see docs.\n\n        With other JPEG optimizations included in this version, we see\n        2x speedup on a JPEG on an x86 machine, and a 1.5x speedup\n        on a JPEG on an ARM machine, relative to previous versions of this\n        library. The same results will not obtain for all JPGs and for all\n        x86/ARM machines. (Note that progressive JPEGs are significantly\n        slower to decode than regular JPEGs.) This doesn't mean that this\n        is the fastest JPEG decoder in the land; rather, it brings it\n        closer to parity with standard libraries. If you want the fastest\n        decode, look elsewhere. (See \"Philosophy\" section of docs below.)\n\n        See final bullet items below for more info on SIMD.\n\n      - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing\n        the memory allocator. Unlike other STBI libraries, these macros don't\n        support a context parameter, so if you need to pass a context in to\n        the allocator, you'll have to store it in a global or a thread-local\n        variable.\n\n      - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and\n        STBI_NO_LINEAR.\n            STBI_NO_HDR:     suppress implementation of .hdr reader format\n            STBI_NO_LINEAR:  suppress high-dynamic-range light-linear float API\n\n      - You can suppress implementation of any of the decoders to reduce\n        your code footprint by #defining one or more of the following\n        symbols before creating the implementation.\n\n            STBI_NO_JPEG\n            STBI_NO_PNG\n            STBI_NO_BMP\n            STBI_NO_PSD\n            STBI_NO_TGA\n            STBI_NO_GIF\n            STBI_NO_HDR\n            STBI_NO_PIC\n            STBI_NO_PNM   (.ppm and .pgm)\n\n      - You can request *only* certain decoders and suppress all other ones\n        (this will be more forward-compatible, as addition of new decoders\n        doesn't require you to disable them explicitly):\n\n            STBI_ONLY_JPEG\n            STBI_ONLY_PNG\n            STBI_ONLY_BMP\n            STBI_ONLY_PSD\n            STBI_ONLY_TGA\n            STBI_ONLY_GIF\n            STBI_ONLY_HDR\n            STBI_ONLY_PIC\n            STBI_ONLY_PNM   (.ppm and .pgm)\n\n         Note that you can define multiples of these, and you will get all\n         of them (\"only x\" and \"only y\" is interpreted to mean \"only x&y\").\n\n       - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still\n         want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB\n\n      - Compilation of all SIMD code can be suppressed with\n            #define STBI_NO_SIMD\n        It should not be necessary to disable SIMD unless you have issues\n        compiling (e.g. using an x86 compiler which doesn't support SSE\n        intrinsics or that doesn't support the method used to detect\n        SSE2 support at run-time), and even those can be reported as\n        bugs so I can refine the built-in compile-time checking to be\n        smarter.\n\n      - The old STBI_SIMD system which allowed installing a user-defined\n        IDCT etc. has been removed. If you need this, don't upgrade. My\n        assumption is that almost nobody was doing this, and those who\n        were will find the built-in SIMD more satisfactory anyway.\n\n      - RGB values computed for JPEG images are slightly different from\n        previous versions of stb_image. (This is due to using less\n        integer precision in SIMD.) The C code has been adjusted so\n        that the same RGB values will be computed regardless of whether\n        SIMD support is available, so your app should always produce\n        consistent results. But these results are slightly different from\n        previous versions. (Specifically, about 3% of available YCbCr values\n        will compute different RGB results from pre-1.49 versions by +-1;\n        most of the deviating values are one smaller in the G channel.)\n\n      - If you must produce consistent results with previous versions of\n        stb_image, #define STBI_JPEG_OLD and you will get the same results\n        you used to; however, you will not get the SIMD speedups for\n        the YCbCr-to-RGB conversion step (although you should still see\n        significant JPEG speedup from the other changes).\n\n        Please note that STBI_JPEG_OLD is a temporary feature; it will be\n        removed in future versions of the library. It is only intended for\n        near-term back-compatibility use.\n\n\n   Latest revision history:\n      2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA\n      2.07  (2015-09-13) partial animated GIF support\n                         limited 16-bit PSD support\n                         minor bugs, code cleanup, and compiler warnings\n      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value\n      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning\n      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit\n      2.03  (2015-04-12) additional corruption checking\n                         stbi_set_flip_vertically_on_load\n                         fix NEON support; fix mingw support\n      2.02  (2015-01-19) fix incorrect assert, fix warning\n      2.01  (2015-01-17) fix various warnings\n      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG\n      2.00  (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD\n                         progressive JPEG\n                         PGM/PPM support\n                         STBI_MALLOC,STBI_REALLOC,STBI_FREE\n                         STBI_NO_*, STBI_ONLY_*\n                         GIF bugfix\n      1.48  (2014-12-14) fix incorrectly-named assert()\n      1.47  (2014-12-14) 1/2/4-bit PNG support (both grayscale and paletted)\n                         optimize PNG\n                         fix bug in interlaced PNG with user-specified channel count\n\n   See end of file for full revision history.\n\n\n ============================    Contributors    =========================\n\n Image formats                                Bug fixes & warning fixes\n    Sean Barrett (jpeg, png, bmp)                Marc LeBlanc\n    Nicolas Schulz (hdr, psd)                    Christpher Lloyd\n    Jonathan Dummer (tga)                        Dave Moore\n    Jean-Marc Lienher (gif)                      Won Chun\n    Tom Seddon (pic)                             the Horde3D community\n    Thatcher Ulrich (psd)                        Janez Zemva\n    Ken Miller (pgm, ppm)                        Jonathan Blow\n    urraka@github (animated gif)                 Laurent Gomila\n                                                 Aruelien Pocheville\n                                                 Ryamond Barbiero\n                                                 David Woo\n Extensions, features                            Martin Golini\n    Jetro Lauha (stbi_info)                      Roy Eltham\n    Martin \"SpartanJ\" Golini (stbi_info)         Luke Graham\n    James \"moose2000\" Brown (iPhone PNG)         Thomas Ruf\n    Ben \"Disch\" Wenger (io callbacks)            John Bartholomew\n    Omar Cornut (1/2/4-bit PNG)                  Ken Hamada\n    Nicolas Guillemot (vertical flip)            Cort Stratton\n    Richard Mitton (16-bit PSD)                  Blazej Dariusz Roszkowski\n                                                 Thibault Reuille\n                                                 Paul Du Bois\n                                                 Guillaume George\n                                                 Jerry Jansson\n                                                 Hayaki Saito\n                                                 Johan Duparc\n                                                 Ronny Chevalier\n Optimizations & bugfixes                        Michal Cichon\n    Fabian \"ryg\" Giesen                          Tero Hanninen\n    Arseny Kapoulkine                            Sergio Gonzalez\n                                                 Cass Everitt\n                                                 Engin Manap\n  If your name should be here but                Martins Mozeiko\n  isn't, let Sean know.                          Joseph Thomson\n                                                 Phil Jordan\n                                                 Nathan Reed\n                                                 Michaelangel007@github\n                                                 Nick Verigakis\n\nLICENSE\n\nThis software is in the public domain. Where that dedication is not\nrecognized, you are granted a perpetual, irrevocable license to copy,\ndistribute, and modify this file as you see fit.\n\n*/\n\n#ifndef STBI_INCLUDE_STB_IMAGE_H\n#define STBI_INCLUDE_STB_IMAGE_H\n\n// DOCUMENTATION\n//\n// Limitations:\n//    - no 16-bit-per-channel PNG\n//    - no 12-bit-per-channel JPEG\n//    - no JPEGs with arithmetic coding\n//    - no 1-bit BMP\n//    - GIF always returns *comp=4\n//\n// Basic usage (see HDR discussion below for HDR usage):\n//    int x,y,n;\n//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);\n//    // ... process data if not NULL ...\n//    // ... x = width, y = height, n = # 8-bit components per pixel ...\n//    // ... replace '0' with '1'..'4' to force that many components per pixel\n//    // ... but 'n' will always be the number that it would have been if you said 0\n//    stbi_image_free(data)\n//\n// Standard parameters:\n//    int *x       -- outputs image width in pixels\n//    int *y       -- outputs image height in pixels\n//    int *comp    -- outputs # of image components in image file\n//    int req_comp -- if non-zero, # of image components requested in result\n//\n// The return value from an image loader is an 'unsigned char *' which points\n// to the pixel data, or NULL on an allocation failure or if the image is\n// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,\n// with each pixel consisting of N interleaved 8-bit components; the first\n// pixel pointed to is top-left-most in the image. There is no padding between\n// image scanlines or between pixels, regardless of format. The number of\n// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.\n// If req_comp is non-zero, *comp has the number of components that _would_\n// have been output otherwise. E.g. if you set req_comp to 4, you will always\n// get RGBA output, but you can check *comp to see if it's trivially opaque\n// because e.g. there were only 3 channels in the source image.\n//\n// An output image with N components has the following components interleaved\n// in this order in each pixel:\n//\n//     N=#comp     components\n//       1           grey\n//       2           grey, alpha\n//       3           red, green, blue\n//       4           red, green, blue, alpha\n//\n// If image loading fails for any reason, the return value will be NULL,\n// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()\n// can be queried for an extremely brief, end-user unfriendly explanation\n// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid\n// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly\n// more user-friendly ones.\n//\n// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.\n//\n// ===========================================================================\n//\n// Philosophy\n//\n// stb libraries are designed with the following priorities:\n//\n//    1. easy to use\n//    2. easy to maintain\n//    3. good performance\n//\n// Sometimes I let \"good performance\" creep up in priority over \"easy to maintain\",\n// and for best performance I may provide less-easy-to-use APIs that give higher\n// performance, in addition to the easy to use ones. Nevertheless, it's important\n// to keep in mind that from the standpoint of you, a client of this library,\n// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all.\n//\n// Some secondary priorities arise directly from the first two, some of which\n// make more explicit reasons why performance can't be emphasized.\n//\n//    - Portable (\"ease of use\")\n//    - Small footprint (\"easy to maintain\")\n//    - No dependencies (\"ease of use\")\n//\n// ===========================================================================\n//\n// I/O callbacks\n//\n// I/O callbacks allow you to read from arbitrary sources, like packaged\n// files or some other source. Data read from callbacks are processed\n// through a small internal buffer (currently 128 bytes) to try to reduce\n// overhead.\n//\n// The three functions you must define are \"read\" (reads some bytes of data),\n// \"skip\" (skips some bytes of data), \"eof\" (reports if the stream is at the end).\n//\n// ===========================================================================\n//\n// SIMD support\n//\n// The JPEG decoder will try to automatically use SIMD kernels on x86 when\n// supported by the compiler. For ARM Neon support, you must explicitly\n// request it.\n//\n// (The old do-it-yourself SIMD API is no longer supported in the current\n// code.)\n//\n// On x86, SSE2 will automatically be used when available based on a run-time\n// test; if not, the generic C versions are used as a fall-back. On ARM targets,\n// the typical path is to have separate builds for NEON and non-NEON devices\n// (at least this is true for iOS and Android). Therefore, the NEON support is\n// toggled by a build flag: define STBI_NEON to get NEON loops.\n//\n// The output of the JPEG decoder is slightly different from versions where\n// SIMD support was introduced (that is, for versions before 1.49). The\n// difference is only +-1 in the 8-bit RGB channels, and only on a small\n// fraction of pixels. You can force the pre-1.49 behavior by defining\n// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path\n// and hence cost some performance.\n//\n// If for some reason you do not want to use any of SIMD code, or if\n// you have issues compiling it, you can disable it entirely by\n// defining STBI_NO_SIMD.\n//\n// ===========================================================================\n//\n// HDR image support   (disable by defining STBI_NO_HDR)\n//\n// stb_image now supports loading HDR images in general, and currently\n// the Radiance .HDR file format, although the support is provided\n// generically. You can still load any file through the existing interface;\n// if you attempt to load an HDR file, it will be automatically remapped to\n// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;\n// both of these constants can be reconfigured through this interface:\n//\n//     stbi_hdr_to_ldr_gamma(2.2f);\n//     stbi_hdr_to_ldr_scale(1.0f);\n//\n// (note, do not use _inverse_ constants; stbi_image will invert them\n// appropriately).\n//\n// Additionally, there is a new, parallel interface for loading files as\n// (linear) floats to preserve the full dynamic range:\n//\n//    float *data = stbi_loadf(filename, &x, &y, &n, 0);\n//\n// If you load LDR images through this interface, those images will\n// be promoted to floating point values, run through the inverse of\n// constants corresponding to the above:\n//\n//     stbi_ldr_to_hdr_scale(1.0f);\n//     stbi_ldr_to_hdr_gamma(2.2f);\n//\n// Finally, given a filename (or an open file or memory block--see header\n// file for details) containing image data, you can query for the \"most\n// appropriate\" interface to use (that is, whether the image is HDR or\n// not), using:\n//\n//     stbi_is_hdr(char *filename);\n//\n// ===========================================================================\n//\n// iPhone PNG support:\n//\n// By default we convert iphone-formatted PNGs back to RGB, even though\n// they are internally encoded differently. You can disable this conversion\n// by by calling stbi_convert_iphone_png_to_rgb(0), in which case\n// you will always just get the native iphone \"format\" through (which\n// is BGR stored in RGB).\n//\n// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per\n// pixel to remove any premultiplied alpha *only* if the image file explicitly\n// says there's premultiplied data (currently only happens in iPhone images,\n// and only if iPhone convert-to-rgb processing is on).\n//\n\n\n#ifndef STBI_NO_STDIO\n#include <stdio.h>\n#endif // STBI_NO_STDIO\n\n#define STBI_VERSION 1\n\nenum\n{\n   STBI_default = 0, // only used for req_comp\n\n   STBI_grey       = 1,\n   STBI_grey_alpha = 2,\n   STBI_rgb        = 3,\n   STBI_rgb_alpha  = 4\n};\n\ntypedef unsigned char stbi_uc;\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifdef STB_IMAGE_STATIC\n#define STBIDEF static\n#else\n#define STBIDEF extern\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// PRIMARY API - works on images of any type\n//\n\n//\n// load image by filename, open file, or memory buffer\n//\n\ntypedef struct\n{\n   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read\n   void     (*skip)  (void *user,int n);                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative\n   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data\n} stbi_io_callbacks;\n\nSTBIDEF stbi_uc *stbi_load               (char              const *filename,           int *x, int *y, int *comp, int req_comp);\nSTBIDEF stbi_uc *stbi_load_from_memory   (stbi_uc           const *buffer, int len   , int *x, int *y, int *comp, int req_comp);\nSTBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk  , void *user, int *x, int *y, int *comp, int req_comp);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF stbi_uc *stbi_load_from_file  (FILE *f,                  int *x, int *y, int *comp, int req_comp);\n// for stbi_load_from_file, file pointer is left pointing immediately after image\n#endif\n\n#ifndef STBI_NO_LINEAR\n   STBIDEF float *stbi_loadf                 (char const *filename,           int *x, int *y, int *comp, int req_comp);\n   STBIDEF float *stbi_loadf_from_memory     (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);\n   STBIDEF float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);\n\n   #ifndef STBI_NO_STDIO\n   STBIDEF float *stbi_loadf_from_file  (FILE *f,                int *x, int *y, int *comp, int req_comp);\n   #endif\n#endif\n\n#ifndef STBI_NO_HDR\n   STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma);\n   STBIDEF void   stbi_hdr_to_ldr_scale(float scale);\n#endif\n\n#ifndef STBI_NO_LINEAR\n   STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma);\n   STBIDEF void   stbi_ldr_to_hdr_scale(float scale);\n#endif // STBI_NO_HDR\n\n// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR\nSTBIDEF int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);\nSTBIDEF int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_is_hdr          (char const *filename);\nSTBIDEF int      stbi_is_hdr_from_file(FILE *f);\n#endif // STBI_NO_STDIO\n\n\n// get a VERY brief reason for failure\n// NOT THREADSAFE\nSTBIDEF const char *stbi_failure_reason  (void);\n\n// free the loaded image -- this is just free()\nSTBIDEF void     stbi_image_free      (void *retval_from_stbi_load);\n\n// get image dimensions & components without fully decoding\nSTBIDEF int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);\nSTBIDEF int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_info            (char const *filename,     int *x, int *y, int *comp);\nSTBIDEF int      stbi_info_from_file  (FILE *f,                  int *x, int *y, int *comp);\n\n#endif\n\n\n\n// for image formats that explicitly notate that they have premultiplied alpha,\n// we just return the colors as stored in the file. set this flag to force\n// unpremultiplication. results are undefined if the unpremultiply overflow.\nSTBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);\n\n// indicate whether we should process iphone images back to canonical format,\n// or just pass them through \"as-is\"\nSTBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);\n\n// flip the image vertically, so the first pixel in the output array is the bottom left\nSTBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);\n\n// ZLIB client - used by PNG, available for other purposes\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);\nSTBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);\nSTBIDEF int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);\n\nSTBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);\nSTBIDEF int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);\n\n\n#ifdef __cplusplus\n}\n#endif\n\n//\n//\n////   end header file   /////////////////////////////////////////////////////\n#endif // STBI_INCLUDE_STB_IMAGE_H\n\n#ifdef STB_IMAGE_IMPLEMENTATION\n\n#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \\\n  || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \\\n  || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \\\n  || defined(STBI_ONLY_ZLIB)\n   #ifndef STBI_ONLY_JPEG\n   #define STBI_NO_JPEG\n   #endif\n   #ifndef STBI_ONLY_PNG\n   #define STBI_NO_PNG\n   #endif\n   #ifndef STBI_ONLY_BMP\n   #define STBI_NO_BMP\n   #endif\n   #ifndef STBI_ONLY_PSD\n   #define STBI_NO_PSD\n   #endif\n   #ifndef STBI_ONLY_TGA\n   #define STBI_NO_TGA\n   #endif\n   #ifndef STBI_ONLY_GIF\n   #define STBI_NO_GIF\n   #endif\n   #ifndef STBI_ONLY_HDR\n   #define STBI_NO_HDR\n   #endif\n   #ifndef STBI_ONLY_PIC\n   #define STBI_NO_PIC\n   #endif\n   #ifndef STBI_ONLY_PNM\n   #define STBI_NO_PNM\n   #endif\n#endif\n\n#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)\n#define STBI_NO_ZLIB\n#endif\n\n\n#include <stdarg.h>\n#include <stddef.h> // ptrdiff_t on osx\n#include <stdlib.h>\n#include <string.h>\n\n#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)\n#include <math.h>  // ldexp\n#endif\n\n#ifndef STBI_NO_STDIO\n#include <stdio.h>\n#endif\n\n#ifndef STBI_ASSERT\n#include <assert.h>\n#define STBI_ASSERT(x) assert(x)\n#endif\n\n\n#ifndef _MSC_VER\n   #ifdef __cplusplus\n   #define stbi_inline inline\n   #else\n   #define stbi_inline\n   #endif\n#else\n   #define stbi_inline __forceinline\n#endif\n\n\n#ifdef _MSC_VER\ntypedef unsigned short stbi__uint16;\ntypedef   signed short stbi__int16;\ntypedef unsigned int   stbi__uint32;\ntypedef   signed int   stbi__int32;\n#else\n#include <stdint.h>\ntypedef uint16_t stbi__uint16;\ntypedef int16_t  stbi__int16;\ntypedef uint32_t stbi__uint32;\ntypedef int32_t  stbi__int32;\n#endif\n\n// should produce compiler error if size is wrong\ntypedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];\n\n#ifdef _MSC_VER\n#define STBI_NOTUSED(v)  (void)(v)\n#else\n#define STBI_NOTUSED(v)  (void)sizeof(v)\n#endif\n\n#ifdef _MSC_VER\n#define STBI_HAS_LROTL\n#endif\n\n#ifdef STBI_HAS_LROTL\n   #define stbi_lrot(x,y)  _lrotl(x,y)\n#else\n   #define stbi_lrot(x,y)  (((x) << (y)) | ((x) >> (32 - (y))))\n#endif\n\n#if defined(STBI_MALLOC) && defined(STBI_FREE) && defined(STBI_REALLOC)\n// ok\n#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC)\n// ok\n#else\n#error \"Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC.\"\n#endif\n\n#ifndef STBI_MALLOC\n#define STBI_MALLOC(sz)    malloc(sz)\n#define STBI_REALLOC(p,sz) realloc(p,sz)\n#define STBI_FREE(p)       free(p)\n#endif\n\n// x86/x64 detection\n#if defined(__x86_64__) || defined(_M_X64)\n#define STBI__X64_TARGET\n#elif defined(__i386) || defined(_M_IX86)\n#define STBI__X86_TARGET\n#endif\n\n#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)\n// NOTE: not clear do we actually need this for the 64-bit path?\n// gcc doesn't support sse2 intrinsics unless you compile with -msse2,\n// (but compiling with -msse2 allows the compiler to use SSE2 everywhere;\n// this is just broken and gcc are jerks for not fixing it properly\n// http://www.virtualdub.org/blog/pivot/entry.php?id=363 )\n#define STBI_NO_SIMD\n#endif\n\n#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)\n// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET\n//\n// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the\n// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.\n// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not\n// simultaneously enabling \"-mstackrealign\".\n//\n// See https://github.com/nothings/stb/issues/81 for more information.\n//\n// So default to no SSE2 on 32-bit MinGW. If you've read this far and added\n// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.\n#define STBI_NO_SIMD\n#endif\n\n#if !defined(STBI_NO_SIMD) && defined(STBI__X86_TARGET)\n#define STBI_SSE2\n#include <emmintrin.h>\n\n#ifdef _MSC_VER\n\n#if _MSC_VER >= 1400  // not VC6\n#include <intrin.h> // __cpuid\nstatic int stbi__cpuid3(void)\n{\n   int info[4];\n   __cpuid(info,1);\n   return info[3];\n}\n#else\nstatic int stbi__cpuid3(void)\n{\n   int res;\n   __asm {\n      mov  eax,1\n      cpuid\n      mov  res,edx\n   }\n   return res;\n}\n#endif\n\n#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name\n\nstatic int stbi__sse2_available()\n{\n   int info3 = stbi__cpuid3();\n   return ((info3 >> 26) & 1) != 0;\n}\n#else // assume GCC-style if not VC++\n#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))\n\nstatic int stbi__sse2_available()\n{\n#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later\n   // GCC 4.8+ has a nice way to do this\n   return __builtin_cpu_supports(\"sse2\");\n#else\n   // portable way to do this, preferably without using GCC inline ASM?\n   // just bail for now.\n   return 0;\n#endif\n}\n#endif\n#endif\n\n// ARM NEON\n#if defined(STBI_NO_SIMD) && defined(STBI_NEON)\n#undef STBI_NEON\n#endif\n\n#ifdef STBI_NEON\n#include <arm_neon.h>\n// assume GCC or Clang on ARM targets\n#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))\n#endif\n\n#ifndef STBI_SIMD_ALIGN\n#define STBI_SIMD_ALIGN(type, name) type name\n#endif\n\n///////////////////////////////////////////////\n//\n//  stbi__context struct and start_xxx functions\n\n// stbi__context structure is our basic context used by all images, so it\n// contains all the IO context, plus some basic image information\ntypedef struct\n{\n   stbi__uint32 img_x, img_y;\n   int img_n, img_out_n;\n\n   stbi_io_callbacks io;\n   void *io_user_data;\n\n   int read_from_callbacks;\n   int buflen;\n   stbi_uc buffer_start[128];\n\n   stbi_uc *img_buffer, *img_buffer_end;\n   stbi_uc *img_buffer_original, *img_buffer_original_end;\n} stbi__context;\n\n\nstatic void stbi__refill_buffer(stbi__context *s);\n\n// initialize a memory-decode context\nstatic void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)\n{\n   s->io.read = NULL;\n   s->read_from_callbacks = 0;\n   s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;\n   s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;\n}\n\n// initialize a callback-based context\nstatic void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)\n{\n   s->io = *c;\n   s->io_user_data = user;\n   s->buflen = sizeof(s->buffer_start);\n   s->read_from_callbacks = 1;\n   s->img_buffer_original = s->buffer_start;\n   stbi__refill_buffer(s);\n   s->img_buffer_original_end = s->img_buffer_end;\n}\n\n#ifndef STBI_NO_STDIO\n\nstatic int stbi__stdio_read(void *user, char *data, int size)\n{\n   return (int) fread(data,1,size,(FILE*) user);\n}\n\nstatic void stbi__stdio_skip(void *user, int n)\n{\n   fseek((FILE*) user, n, SEEK_CUR);\n}\n\nstatic int stbi__stdio_eof(void *user)\n{\n   return feof((FILE*) user);\n}\n\nstatic stbi_io_callbacks stbi__stdio_callbacks =\n{\n   stbi__stdio_read,\n   stbi__stdio_skip,\n   stbi__stdio_eof,\n};\n\nstatic void stbi__start_file(stbi__context *s, FILE *f)\n{\n   stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);\n}\n\n//static void stop_file(stbi__context *s) { }\n\n#endif // !STBI_NO_STDIO\n\nstatic void stbi__rewind(stbi__context *s)\n{\n   // conceptually rewind SHOULD rewind to the beginning of the stream,\n   // but we just rewind to the beginning of the initial buffer, because\n   // we only use it after doing 'test', which only ever looks at at most 92 bytes\n   s->img_buffer = s->img_buffer_original;\n   s->img_buffer_end = s->img_buffer_original_end;\n}\n\n#ifndef STBI_NO_JPEG\nstatic int      stbi__jpeg_test(stbi__context *s);\nstatic stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);\nstatic int      stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PNG\nstatic int      stbi__png_test(stbi__context *s);\nstatic stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);\nstatic int      stbi__png_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_BMP\nstatic int      stbi__bmp_test(stbi__context *s);\nstatic stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);\nstatic int      stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_TGA\nstatic int      stbi__tga_test(stbi__context *s);\nstatic stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);\nstatic int      stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PSD\nstatic int      stbi__psd_test(stbi__context *s);\nstatic stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);\nstatic int      stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_HDR\nstatic int      stbi__hdr_test(stbi__context *s);\nstatic float   *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);\nstatic int      stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PIC\nstatic int      stbi__pic_test(stbi__context *s);\nstatic stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);\nstatic int      stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_GIF\nstatic int      stbi__gif_test(stbi__context *s);\nstatic stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);\nstatic int      stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n#ifndef STBI_NO_PNM\nstatic int      stbi__pnm_test(stbi__context *s);\nstatic stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);\nstatic int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);\n#endif\n\n// this is not threadsafe\nstatic const char *stbi__g_failure_reason;\n\nSTBIDEF const char *stbi_failure_reason(void)\n{\n   return stbi__g_failure_reason;\n}\n\nstatic int stbi__err(const char *str)\n{\n   stbi__g_failure_reason = str;\n   return 0;\n}\n\nstatic void *stbi__malloc(size_t size)\n{\n    return STBI_MALLOC(size);\n}\n\n// stbi__err - error\n// stbi__errpf - error returning pointer to float\n// stbi__errpuc - error returning pointer to unsigned char\n\n#ifdef STBI_NO_FAILURE_STRINGS\n   #define stbi__err(x,y)  0\n#elif defined(STBI_FAILURE_USERMSG)\n   #define stbi__err(x,y)  stbi__err(y)\n#else\n   #define stbi__err(x,y)  stbi__err(x)\n#endif\n\n#define stbi__errpf(x,y)   ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))\n#define stbi__errpuc(x,y)  ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))\n\nSTBIDEF void stbi_image_free(void *retval_from_stbi_load)\n{\n   STBI_FREE(retval_from_stbi_load);\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);\n#endif\n\n#ifndef STBI_NO_HDR\nstatic stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp);\n#endif\n\nstatic int stbi__vertically_flip_on_load = 0;\n\nSTBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)\n{\n    stbi__vertically_flip_on_load = flag_true_if_should_flip;\n}\n\nstatic unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   #ifndef STBI_NO_JPEG\n   if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp);\n   #endif\n   #ifndef STBI_NO_PNG\n   if (stbi__png_test(s))  return stbi__png_load(s,x,y,comp,req_comp);\n   #endif\n   #ifndef STBI_NO_BMP\n   if (stbi__bmp_test(s))  return stbi__bmp_load(s,x,y,comp,req_comp);\n   #endif\n   #ifndef STBI_NO_GIF\n   if (stbi__gif_test(s))  return stbi__gif_load(s,x,y,comp,req_comp);\n   #endif\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_test(s))  return stbi__psd_load(s,x,y,comp,req_comp);\n   #endif\n   #ifndef STBI_NO_PIC\n   if (stbi__pic_test(s))  return stbi__pic_load(s,x,y,comp,req_comp);\n   #endif\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_test(s))  return stbi__pnm_load(s,x,y,comp,req_comp);\n   #endif\n\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_test(s)) {\n      float *hdr = stbi__hdr_load(s, x,y,comp,req_comp);\n      return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);\n   }\n   #endif\n\n   #ifndef STBI_NO_TGA\n   // test tga last because it's a crappy test!\n   if (stbi__tga_test(s))\n      return stbi__tga_load(s,x,y,comp,req_comp);\n   #endif\n\n   return stbi__errpuc(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nstatic unsigned char *stbi__load_flip(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   unsigned char *result = stbi__load_main(s, x, y, comp, req_comp);\n\n   if (stbi__vertically_flip_on_load && result != NULL) {\n      int w = *x, h = *y;\n      int depth = req_comp ? req_comp : *comp;\n      int row,col,z;\n      stbi_uc temp;\n\n      // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once\n      for (row = 0; row < (h>>1); row++) {\n         for (col = 0; col < w; col++) {\n            for (z = 0; z < depth; z++) {\n               temp = result[(row * w + col) * depth + z];\n               result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];\n               result[((h - row - 1) * w + col) * depth + z] = temp;\n            }\n         }\n      }\n   }\n\n   return result;\n}\n\n#ifndef STBI_NO_HDR\nstatic void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)\n{\n   if (stbi__vertically_flip_on_load && result != NULL) {\n      int w = *x, h = *y;\n      int depth = req_comp ? req_comp : *comp;\n      int row,col,z;\n      float temp;\n\n      // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once\n      for (row = 0; row < (h>>1); row++) {\n         for (col = 0; col < w; col++) {\n            for (z = 0; z < depth; z++) {\n               temp = result[(row * w + col) * depth + z];\n               result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];\n               result[((h - row - 1) * w + col) * depth + z] = temp;\n            }\n         }\n      }\n   }\n}\n#endif\n\n#ifndef STBI_NO_STDIO\n\nstatic FILE *stbi__fopen(char const *filename, char const *mode)\n{\n   FILE *f;\n#if defined(_MSC_VER) && _MSC_VER >= 1400\n   if (0 != fopen_s(&f, filename, mode))\n      f=0;\n#else\n   f = fopen(filename, mode);\n#endif\n   return f;\n}\n\n\nSTBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   unsigned char *result;\n   if (!f) return stbi__errpuc(\"can't fopen\", \"Unable to open file\");\n   result = stbi_load_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\nSTBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   unsigned char *result;\n   stbi__context s;\n   stbi__start_file(&s,f);\n   result = stbi__load_flip(&s,x,y,comp,req_comp);\n   if (result) {\n      // need to 'unget' all the characters in the IO buffer\n      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);\n   }\n   return result;\n}\n#endif //!STBI_NO_STDIO\n\nSTBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__load_flip(&s,x,y,comp,req_comp);\n}\n\nSTBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__load_flip(&s,x,y,comp,req_comp);\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   unsigned char *data;\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_test(s)) {\n      float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp);\n      if (hdr_data)\n         stbi__float_postprocess(hdr_data,x,y,comp,req_comp);\n      return hdr_data;\n   }\n   #endif\n   data = stbi__load_flip(s, x, y, comp, req_comp);\n   if (data)\n      return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);\n   return stbi__errpf(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\nSTBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n\nSTBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)\n{\n   float *result;\n   FILE *f = stbi__fopen(filename, \"rb\");\n   if (!f) return stbi__errpf(\"can't fopen\", \"Unable to open file\");\n   result = stbi_loadf_from_file(f,x,y,comp,req_comp);\n   fclose(f);\n   return result;\n}\n\nSTBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__context s;\n   stbi__start_file(&s,f);\n   return stbi__loadf_main(&s,x,y,comp,req_comp);\n}\n#endif // !STBI_NO_STDIO\n\n#endif // !STBI_NO_LINEAR\n\n// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is\n// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always\n// reports false!\n\nSTBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)\n{\n   #ifndef STBI_NO_HDR\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__hdr_test(&s);\n   #else\n   STBI_NOTUSED(buffer);\n   STBI_NOTUSED(len);\n   return 0;\n   #endif\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int      stbi_is_hdr          (char const *filename)\n{\n   FILE *f = stbi__fopen(filename, \"rb\");\n   int result=0;\n   if (f) {\n      result = stbi_is_hdr_from_file(f);\n      fclose(f);\n   }\n   return result;\n}\n\nSTBIDEF int      stbi_is_hdr_from_file(FILE *f)\n{\n   #ifndef STBI_NO_HDR\n   stbi__context s;\n   stbi__start_file(&s,f);\n   return stbi__hdr_test(&s);\n   #else\n   STBI_NOTUSED(f);\n   return 0;\n   #endif\n}\n#endif // !STBI_NO_STDIO\n\nSTBIDEF int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)\n{\n   #ifndef STBI_NO_HDR\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);\n   return stbi__hdr_test(&s);\n   #else\n   STBI_NOTUSED(clbk);\n   STBI_NOTUSED(user);\n   return 0;\n   #endif\n}\n\nstatic float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;\nstatic float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;\n\n#ifndef STBI_NO_LINEAR\nSTBIDEF void   stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }\nSTBIDEF void   stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }\n#endif\n\nSTBIDEF void   stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }\nSTBIDEF void   stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Common code used by all image loaders\n//\n\nenum\n{\n   STBI__SCAN_load=0,\n   STBI__SCAN_type,\n   STBI__SCAN_header\n};\n\nstatic void stbi__refill_buffer(stbi__context *s)\n{\n   int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);\n   if (n == 0) {\n      // at end of file, treat same as if from memory, but need to handle case\n      // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file\n      s->read_from_callbacks = 0;\n      s->img_buffer = s->buffer_start;\n      s->img_buffer_end = s->buffer_start+1;\n      *s->img_buffer = 0;\n   } else {\n      s->img_buffer = s->buffer_start;\n      s->img_buffer_end = s->buffer_start + n;\n   }\n}\n\nstbi_inline static stbi_uc stbi__get8(stbi__context *s)\n{\n   if (s->img_buffer < s->img_buffer_end)\n      return *s->img_buffer++;\n   if (s->read_from_callbacks) {\n      stbi__refill_buffer(s);\n      return *s->img_buffer++;\n   }\n   return 0;\n}\n\nstbi_inline static int stbi__at_eof(stbi__context *s)\n{\n   if (s->io.read) {\n      if (!(s->io.eof)(s->io_user_data)) return 0;\n      // if feof() is true, check if buffer = end\n      // special case: we've only got the special 0 character at the end\n      if (s->read_from_callbacks == 0) return 1;\n   }\n\n   return s->img_buffer >= s->img_buffer_end;\n}\n\nstatic void stbi__skip(stbi__context *s, int n)\n{\n   if (n < 0) {\n      s->img_buffer = s->img_buffer_end;\n      return;\n   }\n   if (s->io.read) {\n      int blen = (int) (s->img_buffer_end - s->img_buffer);\n      if (blen < n) {\n         s->img_buffer = s->img_buffer_end;\n         (s->io.skip)(s->io_user_data, n - blen);\n         return;\n      }\n   }\n   s->img_buffer += n;\n}\n\nstatic int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)\n{\n   if (s->io.read) {\n      int blen = (int) (s->img_buffer_end - s->img_buffer);\n      if (blen < n) {\n         int res, count;\n\n         memcpy(buffer, s->img_buffer, blen);\n\n         count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);\n         res = (count == (n-blen));\n         s->img_buffer = s->img_buffer_end;\n         return res;\n      }\n   }\n\n   if (s->img_buffer+n <= s->img_buffer_end) {\n      memcpy(buffer, s->img_buffer, n);\n      s->img_buffer += n;\n      return 1;\n   } else\n      return 0;\n}\n\nstatic int stbi__get16be(stbi__context *s)\n{\n   int z = stbi__get8(s);\n   return (z << 8) + stbi__get8(s);\n}\n\nstatic stbi__uint32 stbi__get32be(stbi__context *s)\n{\n   stbi__uint32 z = stbi__get16be(s);\n   return (z << 16) + stbi__get16be(s);\n}\n\n#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)\n// nothing\n#else\nstatic int stbi__get16le(stbi__context *s)\n{\n   int z = stbi__get8(s);\n   return z + (stbi__get8(s) << 8);\n}\n#endif\n\n#ifndef STBI_NO_BMP\nstatic stbi__uint32 stbi__get32le(stbi__context *s)\n{\n   stbi__uint32 z = stbi__get16le(s);\n   return z + (stbi__get16le(s) << 16);\n}\n#endif\n\n#define STBI__BYTECAST(x)  ((stbi_uc) ((x) & 255))  // truncate int to byte without warnings\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//  generic converter from built-in img_n to req_comp\n//    individual types do this automatically as much as possible (e.g. jpeg\n//    does all cases internally since it needs to colorspace convert anyway,\n//    and it never has alpha, so very few cases ). png can automatically\n//    interleave an alpha=255 channel, but falls back to this for other cases\n//\n//  assume data buffer is malloced, so malloc a new one and free that one\n//  only failure mode is malloc failing\n\nstatic stbi_uc stbi__compute_y(int r, int g, int b)\n{\n   return (stbi_uc) (((r*77) + (g*150) +  (29*b)) >> 8);\n}\n\nstatic unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)\n{\n   int i,j;\n   unsigned char *good;\n\n   if (req_comp == img_n) return data;\n   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);\n\n   good = (unsigned char *) stbi__malloc(req_comp * x * y);\n   if (good == NULL) {\n      STBI_FREE(data);\n      return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   }\n\n   for (j=0; j < (int) y; ++j) {\n      unsigned char *src  = data + j * x * img_n   ;\n      unsigned char *dest = good + j * x * req_comp;\n\n      #define COMBO(a,b)  ((a)*8+(b))\n      #define CASE(a,b)   case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)\n      // convert source image with img_n components to one with req_comp components;\n      // avoid switch per pixel, so use switch per scanline and massive macros\n      switch (COMBO(img_n, req_comp)) {\n         CASE(1,2) dest[0]=src[0], dest[1]=255; break;\n         CASE(1,3) dest[0]=dest[1]=dest[2]=src[0]; break;\n         CASE(1,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; break;\n         CASE(2,1) dest[0]=src[0]; break;\n         CASE(2,3) dest[0]=dest[1]=dest[2]=src[0]; break;\n         CASE(2,4) dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; break;\n         CASE(3,4) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; break;\n         CASE(3,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break;\n         CASE(3,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; break;\n         CASE(4,1) dest[0]=stbi__compute_y(src[0],src[1],src[2]); break;\n         CASE(4,2) dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; break;\n         CASE(4,3) dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; break;\n         default: STBI_ASSERT(0);\n      }\n      #undef CASE\n   }\n\n   STBI_FREE(data);\n   return good;\n}\n\n#ifndef STBI_NO_LINEAR\nstatic float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)\n{\n   int i,k,n;\n   float *output = (float *) stbi__malloc(x * y * comp * sizeof(float));\n   if (output == NULL) { STBI_FREE(data); return stbi__errpf(\"outofmem\", \"Out of memory\"); }\n   // compute number of non-alpha components\n   if (comp & 1) n = comp; else n = comp-1;\n   for (i=0; i < x*y; ++i) {\n      for (k=0; k < n; ++k) {\n         output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);\n      }\n      if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f;\n   }\n   STBI_FREE(data);\n   return output;\n}\n#endif\n\n#ifndef STBI_NO_HDR\n#define stbi__float2int(x)   ((int) (x))\nstatic stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp)\n{\n   int i,k,n;\n   stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp);\n   if (output == NULL) { STBI_FREE(data); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n   // compute number of non-alpha components\n   if (comp & 1) n = comp; else n = comp-1;\n   for (i=0; i < x*y; ++i) {\n      for (k=0; k < n; ++k) {\n         float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;\n         if (z < 0) z = 0;\n         if (z > 255) z = 255;\n         output[i*comp + k] = (stbi_uc) stbi__float2int(z);\n      }\n      if (k < comp) {\n         float z = data[i*comp+k] * 255 + 0.5f;\n         if (z < 0) z = 0;\n         if (z > 255) z = 255;\n         output[i*comp + k] = (stbi_uc) stbi__float2int(z);\n      }\n   }\n   STBI_FREE(data);\n   return output;\n}\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//  \"baseline\" JPEG/JFIF decoder\n//\n//    simple implementation\n//      - doesn't support delayed output of y-dimension\n//      - simple interface (only one output format: 8-bit interleaved RGB)\n//      - doesn't try to recover corrupt jpegs\n//      - doesn't allow partial loading, loading multiple at once\n//      - still fast on x86 (copying globals into locals doesn't help x86)\n//      - allocates lots of intermediate memory (full size of all components)\n//        - non-interleaved case requires this anyway\n//        - allows good upsampling (see next)\n//    high-quality\n//      - upsampled channels are bilinearly interpolated, even across blocks\n//      - quality integer IDCT derived from IJG's 'slow'\n//    performance\n//      - fast huffman; reasonable integer IDCT\n//      - some SIMD kernels for common paths on targets with SSE2/NEON\n//      - uses a lot of intermediate memory, could cache poorly\n\n#ifndef STBI_NO_JPEG\n\n// huffman decoding acceleration\n#define FAST_BITS   9  // larger handles more cases; smaller stomps less cache\n\ntypedef struct\n{\n   stbi_uc  fast[1 << FAST_BITS];\n   // weirdly, repacking this into AoS is a 10% speed loss, instead of a win\n   stbi__uint16 code[256];\n   stbi_uc  values[256];\n   stbi_uc  size[257];\n   unsigned int maxcode[18];\n   int    delta[17];   // old 'firstsymbol' - old 'firstcode'\n} stbi__huffman;\n\ntypedef struct\n{\n   stbi__context *s;\n   stbi__huffman huff_dc[4];\n   stbi__huffman huff_ac[4];\n   stbi_uc dequant[4][64];\n   stbi__int16 fast_ac[4][1 << FAST_BITS];\n\n// sizes for components, interleaved MCUs\n   int img_h_max, img_v_max;\n   int img_mcu_x, img_mcu_y;\n   int img_mcu_w, img_mcu_h;\n\n// definition of jpeg image component\n   struct\n   {\n      int id;\n      int h,v;\n      int tq;\n      int hd,ha;\n      int dc_pred;\n\n      int x,y,w2,h2;\n      stbi_uc *data;\n      void *raw_data, *raw_coeff;\n      stbi_uc *linebuf;\n      short   *coeff;   // progressive only\n      int      coeff_w, coeff_h; // number of 8x8 coefficient blocks\n   } img_comp[4];\n\n   stbi__uint32   code_buffer; // jpeg entropy-coded buffer\n   int            code_bits;   // number of valid bits\n   unsigned char  marker;      // marker seen while filling entropy buffer\n   int            nomore;      // flag if we saw a marker so must stop\n\n   int            progressive;\n   int            spec_start;\n   int            spec_end;\n   int            succ_high;\n   int            succ_low;\n   int            eob_run;\n\n   int scan_n, order[4];\n   int restart_interval, todo;\n\n// kernels\n   void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);\n   void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);\n   stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);\n} stbi__jpeg;\n\nstatic int stbi__build_huffman(stbi__huffman *h, int *count)\n{\n   int i,j,k=0,code;\n   // build size list for each symbol (from JPEG spec)\n   for (i=0; i < 16; ++i)\n      for (j=0; j < count[i]; ++j)\n         h->size[k++] = (stbi_uc) (i+1);\n   h->size[k] = 0;\n\n   // compute actual symbols (from jpeg spec)\n   code = 0;\n   k = 0;\n   for(j=1; j <= 16; ++j) {\n      // compute delta to add to code to compute symbol id\n      h->delta[j] = k - code;\n      if (h->size[k] == j) {\n         while (h->size[k] == j)\n            h->code[k++] = (stbi__uint16) (code++);\n         if (code-1 >= (1 << j)) return stbi__err(\"bad code lengths\",\"Corrupt JPEG\");\n      }\n      // compute largest code + 1 for this size, preshifted as needed later\n      h->maxcode[j] = code << (16-j);\n      code <<= 1;\n   }\n   h->maxcode[j] = 0xffffffff;\n\n   // build non-spec acceleration table; 255 is flag for not-accelerated\n   memset(h->fast, 255, 1 << FAST_BITS);\n   for (i=0; i < k; ++i) {\n      int s = h->size[i];\n      if (s <= FAST_BITS) {\n         int c = h->code[i] << (FAST_BITS-s);\n         int m = 1 << (FAST_BITS-s);\n         for (j=0; j < m; ++j) {\n            h->fast[c+j] = (stbi_uc) i;\n         }\n      }\n   }\n   return 1;\n}\n\n// build a table that decodes both magnitude and value of small ACs in\n// one go.\nstatic void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)\n{\n   int i;\n   for (i=0; i < (1 << FAST_BITS); ++i) {\n      stbi_uc fast = h->fast[i];\n      fast_ac[i] = 0;\n      if (fast < 255) {\n         int rs = h->values[fast];\n         int run = (rs >> 4) & 15;\n         int magbits = rs & 15;\n         int len = h->size[fast];\n\n         if (magbits && len + magbits <= FAST_BITS) {\n            // magnitude code followed by receive_extend code\n            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);\n            int m = 1 << (magbits - 1);\n            if (k < m) k += (-1 << magbits) + 1;\n            // if the result is small enough, we can fit it in fast_ac table\n            if (k >= -128 && k <= 127)\n               fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits));\n         }\n      }\n   }\n}\n\nstatic void stbi__grow_buffer_unsafe(stbi__jpeg *j)\n{\n   do {\n      int b = j->nomore ? 0 : stbi__get8(j->s);\n      if (b == 0xff) {\n         int c = stbi__get8(j->s);\n         if (c != 0) {\n            j->marker = (unsigned char) c;\n            j->nomore = 1;\n            return;\n         }\n      }\n      j->code_buffer |= b << (24 - j->code_bits);\n      j->code_bits += 8;\n   } while (j->code_bits <= 24);\n}\n\n// (1 << n) - 1\nstatic stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};\n\n// decode a jpeg huffman value from the bitstream\nstbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)\n{\n   unsigned int temp;\n   int c,k;\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n\n   // look at the top FAST_BITS and determine what symbol ID it is,\n   // if the code is <= FAST_BITS\n   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n   k = h->fast[c];\n   if (k < 255) {\n      int s = h->size[k];\n      if (s > j->code_bits)\n         return -1;\n      j->code_buffer <<= s;\n      j->code_bits -= s;\n      return h->values[k];\n   }\n\n   // naive test is to shift the code_buffer down so k bits are\n   // valid, then test against maxcode. To speed this up, we've\n   // preshifted maxcode left so that it has (16-k) 0s at the\n   // end; in other words, regardless of the number of bits, it\n   // wants to be compared against something shifted to have 16;\n   // that way we don't need to shift inside the loop.\n   temp = j->code_buffer >> 16;\n   for (k=FAST_BITS+1 ; ; ++k)\n      if (temp < h->maxcode[k])\n         break;\n   if (k == 17) {\n      // error! code not found\n      j->code_bits -= 16;\n      return -1;\n   }\n\n   if (k > j->code_bits)\n      return -1;\n\n   // convert the huffman code to the symbol id\n   c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];\n   STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);\n\n   // convert the id to a symbol\n   j->code_bits -= k;\n   j->code_buffer <<= k;\n   return h->values[c];\n}\n\n// bias[n] = (-1<<n) + 1\nstatic int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};\n\n// combined JPEG 'receive' and JPEG 'extend', since baseline\n// always extends everything it receives.\nstbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)\n{\n   unsigned int k;\n   int sgn;\n   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);\n\n   sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB\n   k = stbi_lrot(j->code_buffer, n);\n   STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask)));\n   j->code_buffer = k & ~stbi__bmask[n];\n   k &= stbi__bmask[n];\n   j->code_bits -= n;\n   return k + (stbi__jbias[n] & ~sgn);\n}\n\n// get some unsigned bits\nstbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)\n{\n   unsigned int k;\n   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);\n   k = stbi_lrot(j->code_buffer, n);\n   j->code_buffer = k & ~stbi__bmask[n];\n   k &= stbi__bmask[n];\n   j->code_bits -= n;\n   return k;\n}\n\nstbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)\n{\n   unsigned int k;\n   if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);\n   k = j->code_buffer;\n   j->code_buffer <<= 1;\n   --j->code_bits;\n   return k & 0x80000000;\n}\n\n// given a value that's at position X in the zigzag stream,\n// where does it appear in the 8x8 matrix coded as row-major?\nstatic stbi_uc stbi__jpeg_dezigzag[64+15] =\n{\n    0,  1,  8, 16,  9,  2,  3, 10,\n   17, 24, 32, 25, 18, 11,  4,  5,\n   12, 19, 26, 33, 40, 48, 41, 34,\n   27, 20, 13,  6,  7, 14, 21, 28,\n   35, 42, 49, 56, 57, 50, 43, 36,\n   29, 22, 15, 23, 30, 37, 44, 51,\n   58, 59, 52, 45, 38, 31, 39, 46,\n   53, 60, 61, 54, 47, 55, 62, 63,\n   // let corrupt input sample past end\n   63, 63, 63, 63, 63, 63, 63, 63,\n   63, 63, 63, 63, 63, 63, 63\n};\n\n// decode one 64-entry block--\nstatic int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant)\n{\n   int diff,dc,k;\n   int t;\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n   t = stbi__jpeg_huff_decode(j, hdc);\n   if (t < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n\n   // 0 all the ac values now so we can do it 32-bits at a time\n   memset(data,0,64*sizeof(data[0]));\n\n   diff = t ? stbi__extend_receive(j, t) : 0;\n   dc = j->img_comp[b].dc_pred + diff;\n   j->img_comp[b].dc_pred = dc;\n   data[0] = (short) (dc * dequant[0]);\n\n   // decode AC components, see JPEG spec\n   k = 1;\n   do {\n      unsigned int zig;\n      int c,r,s;\n      if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n      r = fac[c];\n      if (r) { // fast-AC path\n         k += (r >> 4) & 15; // run\n         s = r & 15; // combined length\n         j->code_buffer <<= s;\n         j->code_bits -= s;\n         // decode into unzigzag'd location\n         zig = stbi__jpeg_dezigzag[k++];\n         data[zig] = (short) ((r >> 8) * dequant[zig]);\n      } else {\n         int rs = stbi__jpeg_huff_decode(j, hac);\n         if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n         s = rs & 15;\n         r = rs >> 4;\n         if (s == 0) {\n            if (rs != 0xf0) break; // end block\n            k += 16;\n         } else {\n            k += r;\n            // decode into unzigzag'd location\n            zig = stbi__jpeg_dezigzag[k++];\n            data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);\n         }\n      }\n   } while (k < 64);\n   return 1;\n}\n\nstatic int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)\n{\n   int diff,dc;\n   int t;\n   if (j->spec_end != 0) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n\n   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n\n   if (j->succ_high == 0) {\n      // first scan for DC coefficient, must be first\n      memset(data,0,64*sizeof(data[0])); // 0 all the ac values now\n      t = stbi__jpeg_huff_decode(j, hdc);\n      diff = t ? stbi__extend_receive(j, t) : 0;\n\n      dc = j->img_comp[b].dc_pred + diff;\n      j->img_comp[b].dc_pred = dc;\n      data[0] = (short) (dc << j->succ_low);\n   } else {\n      // refinement scan for DC coefficient\n      if (stbi__jpeg_get_bit(j))\n         data[0] += (short) (1 << j->succ_low);\n   }\n   return 1;\n}\n\n// @OPTIMIZE: store non-zigzagged during the decode passes,\n// and only de-zigzag when dequantizing\nstatic int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)\n{\n   int k;\n   if (j->spec_start == 0) return stbi__err(\"can't merge dc and ac\", \"Corrupt JPEG\");\n\n   if (j->succ_high == 0) {\n      int shift = j->succ_low;\n\n      if (j->eob_run) {\n         --j->eob_run;\n         return 1;\n      }\n\n      k = j->spec_start;\n      do {\n         unsigned int zig;\n         int c,r,s;\n         if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);\n         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);\n         r = fac[c];\n         if (r) { // fast-AC path\n            k += (r >> 4) & 15; // run\n            s = r & 15; // combined length\n            j->code_buffer <<= s;\n            j->code_bits -= s;\n            zig = stbi__jpeg_dezigzag[k++];\n            data[zig] = (short) ((r >> 8) << shift);\n         } else {\n            int rs = stbi__jpeg_huff_decode(j, hac);\n            if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n            s = rs & 15;\n            r = rs >> 4;\n            if (s == 0) {\n               if (r < 15) {\n                  j->eob_run = (1 << r);\n                  if (r)\n                     j->eob_run += stbi__jpeg_get_bits(j, r);\n                  --j->eob_run;\n                  break;\n               }\n               k += 16;\n            } else {\n               k += r;\n               zig = stbi__jpeg_dezigzag[k++];\n               data[zig] = (short) (stbi__extend_receive(j,s) << shift);\n            }\n         }\n      } while (k <= j->spec_end);\n   } else {\n      // refinement scan for these AC coefficients\n\n      short bit = (short) (1 << j->succ_low);\n\n      if (j->eob_run) {\n         --j->eob_run;\n         for (k = j->spec_start; k <= j->spec_end; ++k) {\n            short *p = &data[stbi__jpeg_dezigzag[k]];\n            if (*p != 0)\n               if (stbi__jpeg_get_bit(j))\n                  if ((*p & bit)==0) {\n                     if (*p > 0)\n                        *p += bit;\n                     else\n                        *p -= bit;\n                  }\n         }\n      } else {\n         k = j->spec_start;\n         do {\n            int r,s;\n            int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh\n            if (rs < 0) return stbi__err(\"bad huffman code\",\"Corrupt JPEG\");\n            s = rs & 15;\n            r = rs >> 4;\n            if (s == 0) {\n               if (r < 15) {\n                  j->eob_run = (1 << r) - 1;\n                  if (r)\n                     j->eob_run += stbi__jpeg_get_bits(j, r);\n                  r = 64; // force end of block\n               } else {\n                  // r=15 s=0 should write 16 0s, so we just do\n                  // a run of 15 0s and then write s (which is 0),\n                  // so we don't have to do anything special here\n               }\n            } else {\n               if (s != 1) return stbi__err(\"bad huffman code\", \"Corrupt JPEG\");\n               // sign bit\n               if (stbi__jpeg_get_bit(j))\n                  s = bit;\n               else\n                  s = -bit;\n            }\n\n            // advance by r\n            while (k <= j->spec_end) {\n               short *p = &data[stbi__jpeg_dezigzag[k++]];\n               if (*p != 0) {\n                  if (stbi__jpeg_get_bit(j))\n                     if ((*p & bit)==0) {\n                        if (*p > 0)\n                           *p += bit;\n                        else\n                           *p -= bit;\n                     }\n               } else {\n                  if (r == 0) {\n                     *p = (short) s;\n                     break;\n                  }\n                  --r;\n               }\n            }\n         } while (k <= j->spec_end);\n      }\n   }\n   return 1;\n}\n\n// take a -128..127 value and stbi__clamp it and convert to 0..255\nstbi_inline static stbi_uc stbi__clamp(int x)\n{\n   // trick to use a single test to catch both cases\n   if ((unsigned int) x > 255) {\n      if (x < 0) return 0;\n      if (x > 255) return 255;\n   }\n   return (stbi_uc) x;\n}\n\n#define stbi__f2f(x)  ((int) (((x) * 4096 + 0.5)))\n#define stbi__fsh(x)  ((x) << 12)\n\n// derived from jidctint -- DCT_ISLOW\n#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \\\n   int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \\\n   p2 = s2;                                    \\\n   p3 = s6;                                    \\\n   p1 = (p2+p3) * stbi__f2f(0.5411961f);       \\\n   t2 = p1 + p3*stbi__f2f(-1.847759065f);      \\\n   t3 = p1 + p2*stbi__f2f( 0.765366865f);      \\\n   p2 = s0;                                    \\\n   p3 = s4;                                    \\\n   t0 = stbi__fsh(p2+p3);                      \\\n   t1 = stbi__fsh(p2-p3);                      \\\n   x0 = t0+t3;                                 \\\n   x3 = t0-t3;                                 \\\n   x1 = t1+t2;                                 \\\n   x2 = t1-t2;                                 \\\n   t0 = s7;                                    \\\n   t1 = s5;                                    \\\n   t2 = s3;                                    \\\n   t3 = s1;                                    \\\n   p3 = t0+t2;                                 \\\n   p4 = t1+t3;                                 \\\n   p1 = t0+t3;                                 \\\n   p2 = t1+t2;                                 \\\n   p5 = (p3+p4)*stbi__f2f( 1.175875602f);      \\\n   t0 = t0*stbi__f2f( 0.298631336f);           \\\n   t1 = t1*stbi__f2f( 2.053119869f);           \\\n   t2 = t2*stbi__f2f( 3.072711026f);           \\\n   t3 = t3*stbi__f2f( 1.501321110f);           \\\n   p1 = p5 + p1*stbi__f2f(-0.899976223f);      \\\n   p2 = p5 + p2*stbi__f2f(-2.562915447f);      \\\n   p3 = p3*stbi__f2f(-1.961570560f);           \\\n   p4 = p4*stbi__f2f(-0.390180644f);           \\\n   t3 += p1+p4;                                \\\n   t2 += p2+p3;                                \\\n   t1 += p2+p4;                                \\\n   t0 += p1+p3;\n\nstatic void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])\n{\n   int i,val[64],*v=val;\n   stbi_uc *o;\n   short *d = data;\n\n   // columns\n   for (i=0; i < 8; ++i,++d, ++v) {\n      // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing\n      if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0\n           && d[40]==0 && d[48]==0 && d[56]==0) {\n         //    no shortcut                 0     seconds\n         //    (1|2|3|4|5|6|7)==0          0     seconds\n         //    all separate               -0.047 seconds\n         //    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds\n         int dcterm = d[0] << 2;\n         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;\n      } else {\n         STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])\n         // constants scaled things up by 1<<12; let's bring them back\n         // down, but keep 2 extra bits of precision\n         x0 += 512; x1 += 512; x2 += 512; x3 += 512;\n         v[ 0] = (x0+t3) >> 10;\n         v[56] = (x0-t3) >> 10;\n         v[ 8] = (x1+t2) >> 10;\n         v[48] = (x1-t2) >> 10;\n         v[16] = (x2+t1) >> 10;\n         v[40] = (x2-t1) >> 10;\n         v[24] = (x3+t0) >> 10;\n         v[32] = (x3-t0) >> 10;\n      }\n   }\n\n   for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {\n      // no fast case since the first 1D IDCT spread components out\n      STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])\n      // constants scaled things up by 1<<12, plus we had 1<<2 from first\n      // loop, plus horizontal and vertical each scale by sqrt(8) so together\n      // we've got an extra 1<<3, so 1<<17 total we need to remove.\n      // so we want to round that, which means adding 0.5 * 1<<17,\n      // aka 65536. Also, we'll end up with -128 to 127 that we want\n      // to encode as 0..255 by adding 128, so we'll add that before the shift\n      x0 += 65536 + (128<<17);\n      x1 += 65536 + (128<<17);\n      x2 += 65536 + (128<<17);\n      x3 += 65536 + (128<<17);\n      // tried computing the shifts into temps, or'ing the temps to see\n      // if any were out of range, but that was slower\n      o[0] = stbi__clamp((x0+t3) >> 17);\n      o[7] = stbi__clamp((x0-t3) >> 17);\n      o[1] = stbi__clamp((x1+t2) >> 17);\n      o[6] = stbi__clamp((x1-t2) >> 17);\n      o[2] = stbi__clamp((x2+t1) >> 17);\n      o[5] = stbi__clamp((x2-t1) >> 17);\n      o[3] = stbi__clamp((x3+t0) >> 17);\n      o[4] = stbi__clamp((x3-t0) >> 17);\n   }\n}\n\n#ifdef STBI_SSE2\n// sse2 integer IDCT. not the fastest possible implementation but it\n// produces bit-identical results to the generic C version so it's\n// fully \"transparent\".\nstatic void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])\n{\n   // This is constructed to match our regular (generic) integer IDCT exactly.\n   __m128i row0, row1, row2, row3, row4, row5, row6, row7;\n   __m128i tmp;\n\n   // dot product constant: even elems=x, odd elems=y\n   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))\n\n   // out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)\n   // out(1) = c1[even]*x + c1[odd]*y\n   #define dct_rot(out0,out1, x,y,c0,c1) \\\n      __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \\\n      __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \\\n      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \\\n      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \\\n      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \\\n      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)\n\n   // out = in << 12  (in 16-bit, out 32-bit)\n   #define dct_widen(out, in) \\\n      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \\\n      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)\n\n   // wide add\n   #define dct_wadd(out, a, b) \\\n      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)\n\n   // wide sub\n   #define dct_wsub(out, a, b) \\\n      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \\\n      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)\n\n   // butterfly a/b, add bias, then shift by \"s\" and pack\n   #define dct_bfly32o(out0, out1, a,b,bias,s) \\\n      { \\\n         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \\\n         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \\\n         dct_wadd(sum, abiased, b); \\\n         dct_wsub(dif, abiased, b); \\\n         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \\\n         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \\\n      }\n\n   // 8-bit interleave step (for transposes)\n   #define dct_interleave8(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi8(a, b); \\\n      b = _mm_unpackhi_epi8(tmp, b)\n\n   // 16-bit interleave step (for transposes)\n   #define dct_interleave16(a, b) \\\n      tmp = a; \\\n      a = _mm_unpacklo_epi16(a, b); \\\n      b = _mm_unpackhi_epi16(tmp, b)\n\n   #define dct_pass(bias,shift) \\\n      { \\\n         /* even part */ \\\n         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \\\n         __m128i sum04 = _mm_add_epi16(row0, row4); \\\n         __m128i dif04 = _mm_sub_epi16(row0, row4); \\\n         dct_widen(t0e, sum04); \\\n         dct_widen(t1e, dif04); \\\n         dct_wadd(x0, t0e, t3e); \\\n         dct_wsub(x3, t0e, t3e); \\\n         dct_wadd(x1, t1e, t2e); \\\n         dct_wsub(x2, t1e, t2e); \\\n         /* odd part */ \\\n         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \\\n         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \\\n         __m128i sum17 = _mm_add_epi16(row1, row7); \\\n         __m128i sum35 = _mm_add_epi16(row3, row5); \\\n         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \\\n         dct_wadd(x4, y0o, y4o); \\\n         dct_wadd(x5, y1o, y5o); \\\n         dct_wadd(x6, y2o, y5o); \\\n         dct_wadd(x7, y3o, y4o); \\\n         dct_bfly32o(row0,row7, x0,x7,bias,shift); \\\n         dct_bfly32o(row1,row6, x1,x6,bias,shift); \\\n         dct_bfly32o(row2,row5, x2,x5,bias,shift); \\\n         dct_bfly32o(row3,row4, x3,x4,bias,shift); \\\n      }\n\n   __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));\n   __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));\n   __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));\n   __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));\n   __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));\n   __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));\n   __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));\n   __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));\n\n   // rounding biases in column/row passes, see stbi__idct_block for explanation.\n   __m128i bias_0 = _mm_set1_epi32(512);\n   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));\n\n   // load\n   row0 = _mm_load_si128((const __m128i *) (data + 0*8));\n   row1 = _mm_load_si128((const __m128i *) (data + 1*8));\n   row2 = _mm_load_si128((const __m128i *) (data + 2*8));\n   row3 = _mm_load_si128((const __m128i *) (data + 3*8));\n   row4 = _mm_load_si128((const __m128i *) (data + 4*8));\n   row5 = _mm_load_si128((const __m128i *) (data + 5*8));\n   row6 = _mm_load_si128((const __m128i *) (data + 6*8));\n   row7 = _mm_load_si128((const __m128i *) (data + 7*8));\n\n   // column pass\n   dct_pass(bias_0, 10);\n\n   {\n      // 16bit 8x8 transpose pass 1\n      dct_interleave16(row0, row4);\n      dct_interleave16(row1, row5);\n      dct_interleave16(row2, row6);\n      dct_interleave16(row3, row7);\n\n      // transpose pass 2\n      dct_interleave16(row0, row2);\n      dct_interleave16(row1, row3);\n      dct_interleave16(row4, row6);\n      dct_interleave16(row5, row7);\n\n      // transpose pass 3\n      dct_interleave16(row0, row1);\n      dct_interleave16(row2, row3);\n      dct_interleave16(row4, row5);\n      dct_interleave16(row6, row7);\n   }\n\n   // row pass\n   dct_pass(bias_1, 17);\n\n   {\n      // pack\n      __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7\n      __m128i p1 = _mm_packus_epi16(row2, row3);\n      __m128i p2 = _mm_packus_epi16(row4, row5);\n      __m128i p3 = _mm_packus_epi16(row6, row7);\n\n      // 8bit 8x8 transpose pass 1\n      dct_interleave8(p0, p2); // a0e0a1e1...\n      dct_interleave8(p1, p3); // c0g0c1g1...\n\n      // transpose pass 2\n      dct_interleave8(p0, p1); // a0c0e0g0...\n      dct_interleave8(p2, p3); // b0d0f0h0...\n\n      // transpose pass 3\n      dct_interleave8(p0, p2); // a0b0c0d0...\n      dct_interleave8(p1, p3); // a4b4c4d4...\n\n      // store\n      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;\n      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));\n   }\n\n#undef dct_const\n#undef dct_rot\n#undef dct_widen\n#undef dct_wadd\n#undef dct_wsub\n#undef dct_bfly32o\n#undef dct_interleave8\n#undef dct_interleave16\n#undef dct_pass\n}\n\n#endif // STBI_SSE2\n\n#ifdef STBI_NEON\n\n// NEON integer IDCT. should produce bit-identical\n// results to the generic C version.\nstatic void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])\n{\n   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;\n\n   int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));\n   int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));\n   int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));\n   int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));\n   int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));\n   int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));\n   int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));\n   int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));\n   int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));\n   int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));\n   int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));\n   int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));\n\n#define dct_long_mul(out, inq, coeff) \\\n   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \\\n   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)\n\n#define dct_long_mac(out, acc, inq, coeff) \\\n   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \\\n   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)\n\n#define dct_widen(out, inq) \\\n   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \\\n   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)\n\n// wide add\n#define dct_wadd(out, a, b) \\\n   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \\\n   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)\n\n// wide sub\n#define dct_wsub(out, a, b) \\\n   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \\\n   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)\n\n// butterfly a/b, then shift using \"shiftop\" by \"s\" and pack\n#define dct_bfly32o(out0,out1, a,b,shiftop,s) \\\n   { \\\n      dct_wadd(sum, a, b); \\\n      dct_wsub(dif, a, b); \\\n      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \\\n      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \\\n   }\n\n#define dct_pass(shiftop, shift) \\\n   { \\\n      /* even part */ \\\n      int16x8_t sum26 = vaddq_s16(row2, row6); \\\n      dct_long_mul(p1e, sum26, rot0_0); \\\n      dct_long_mac(t2e, p1e, row6, rot0_1); \\\n      dct_long_mac(t3e, p1e, row2, rot0_2); \\\n      int16x8_t sum04 = vaddq_s16(row0, row4); \\\n      int16x8_t dif04 = vsubq_s16(row0, row4); \\\n      dct_widen(t0e, sum04); \\\n      dct_widen(t1e, dif04); \\\n      dct_wadd(x0, t0e, t3e); \\\n      dct_wsub(x3, t0e, t3e); \\\n      dct_wadd(x1, t1e, t2e); \\\n      dct_wsub(x2, t1e, t2e); \\\n      /* odd part */ \\\n      int16x8_t sum15 = vaddq_s16(row1, row5); \\\n      int16x8_t sum17 = vaddq_s16(row1, row7); \\\n      int16x8_t sum35 = vaddq_s16(row3, row5); \\\n      int16x8_t sum37 = vaddq_s16(row3, row7); \\\n      int16x8_t sumodd = vaddq_s16(sum17, sum35); \\\n      dct_long_mul(p5o, sumodd, rot1_0); \\\n      dct_long_mac(p1o, p5o, sum17, rot1_1); \\\n      dct_long_mac(p2o, p5o, sum35, rot1_2); \\\n      dct_long_mul(p3o, sum37, rot2_0); \\\n      dct_long_mul(p4o, sum15, rot2_1); \\\n      dct_wadd(sump13o, p1o, p3o); \\\n      dct_wadd(sump24o, p2o, p4o); \\\n      dct_wadd(sump23o, p2o, p3o); \\\n      dct_wadd(sump14o, p1o, p4o); \\\n      dct_long_mac(x4, sump13o, row7, rot3_0); \\\n      dct_long_mac(x5, sump24o, row5, rot3_1); \\\n      dct_long_mac(x6, sump23o, row3, rot3_2); \\\n      dct_long_mac(x7, sump14o, row1, rot3_3); \\\n      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \\\n      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \\\n      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \\\n      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \\\n   }\n\n   // load\n   row0 = vld1q_s16(data + 0*8);\n   row1 = vld1q_s16(data + 1*8);\n   row2 = vld1q_s16(data + 2*8);\n   row3 = vld1q_s16(data + 3*8);\n   row4 = vld1q_s16(data + 4*8);\n   row5 = vld1q_s16(data + 5*8);\n   row6 = vld1q_s16(data + 6*8);\n   row7 = vld1q_s16(data + 7*8);\n\n   // add DC bias\n   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));\n\n   // column pass\n   dct_pass(vrshrn_n_s32, 10);\n\n   // 16bit 8x8 transpose\n   {\n// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.\n// whether compilers actually get this is another story, sadly.\n#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }\n#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }\n#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }\n\n      // pass 1\n      dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6\n      dct_trn16(row2, row3);\n      dct_trn16(row4, row5);\n      dct_trn16(row6, row7);\n\n      // pass 2\n      dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4\n      dct_trn32(row1, row3);\n      dct_trn32(row4, row6);\n      dct_trn32(row5, row7);\n\n      // pass 3\n      dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0\n      dct_trn64(row1, row5);\n      dct_trn64(row2, row6);\n      dct_trn64(row3, row7);\n\n#undef dct_trn16\n#undef dct_trn32\n#undef dct_trn64\n   }\n\n   // row pass\n   // vrshrn_n_s32 only supports shifts up to 16, we need\n   // 17. so do a non-rounding shift of 16 first then follow\n   // up with a rounding shift by 1.\n   dct_pass(vshrn_n_s32, 16);\n\n   {\n      // pack and round\n      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);\n      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);\n      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);\n      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);\n      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);\n      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);\n      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);\n      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);\n\n      // again, these can translate into one instruction, but often don't.\n#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }\n#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }\n#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }\n\n      // sadly can't use interleaved stores here since we only write\n      // 8 bytes to each scan line!\n\n      // 8x8 8-bit transpose pass 1\n      dct_trn8_8(p0, p1);\n      dct_trn8_8(p2, p3);\n      dct_trn8_8(p4, p5);\n      dct_trn8_8(p6, p7);\n\n      // pass 2\n      dct_trn8_16(p0, p2);\n      dct_trn8_16(p1, p3);\n      dct_trn8_16(p4, p6);\n      dct_trn8_16(p5, p7);\n\n      // pass 3\n      dct_trn8_32(p0, p4);\n      dct_trn8_32(p1, p5);\n      dct_trn8_32(p2, p6);\n      dct_trn8_32(p3, p7);\n\n      // store\n      vst1_u8(out, p0); out += out_stride;\n      vst1_u8(out, p1); out += out_stride;\n      vst1_u8(out, p2); out += out_stride;\n      vst1_u8(out, p3); out += out_stride;\n      vst1_u8(out, p4); out += out_stride;\n      vst1_u8(out, p5); out += out_stride;\n      vst1_u8(out, p6); out += out_stride;\n      vst1_u8(out, p7);\n\n#undef dct_trn8_8\n#undef dct_trn8_16\n#undef dct_trn8_32\n   }\n\n#undef dct_long_mul\n#undef dct_long_mac\n#undef dct_widen\n#undef dct_wadd\n#undef dct_wsub\n#undef dct_bfly32o\n#undef dct_pass\n}\n\n#endif // STBI_NEON\n\n#define STBI__MARKER_none  0xff\n// if there's a pending marker from the entropy stream, return that\n// otherwise, fetch from the stream and get a marker. if there's no\n// marker, return 0xff, which is never a valid marker value\nstatic stbi_uc stbi__get_marker(stbi__jpeg *j)\n{\n   stbi_uc x;\n   if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }\n   x = stbi__get8(j->s);\n   if (x != 0xff) return STBI__MARKER_none;\n   while (x == 0xff)\n      x = stbi__get8(j->s);\n   return x;\n}\n\n// in each scan, we'll have scan_n components, and the order\n// of the components is specified by order[]\n#define STBI__RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)\n\n// after a restart interval, stbi__jpeg_reset the entropy decoder and\n// the dc prediction\nstatic void stbi__jpeg_reset(stbi__jpeg *j)\n{\n   j->code_bits = 0;\n   j->code_buffer = 0;\n   j->nomore = 0;\n   j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0;\n   j->marker = STBI__MARKER_none;\n   j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;\n   j->eob_run = 0;\n   // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,\n   // since we don't even allow 1<<30 pixels\n}\n\nstatic int stbi__parse_entropy_coded_data(stbi__jpeg *z)\n{\n   stbi__jpeg_reset(z);\n   if (!z->progressive) {\n      if (z->scan_n == 1) {\n         int i,j;\n         STBI_SIMD_ALIGN(short, data[64]);\n         int n = z->order[0];\n         // non-interleaved data, we just need to process one block at a time,\n         // in trivial scanline order\n         // number of blocks to do just depends on how many actual \"pixels\" this\n         // component has, independent of interleaved MCU blocking and such\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               int ha = z->img_comp[n].ha;\n               if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;\n               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);\n               // every data block is an MCU, so countdown the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  // if it's NOT a restart, then just bail, so we get corrupt data\n                  // rather than no data\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      } else { // interleaved\n         int i,j,k,x,y;\n         STBI_SIMD_ALIGN(short, data[64]);\n         for (j=0; j < z->img_mcu_y; ++j) {\n            for (i=0; i < z->img_mcu_x; ++i) {\n               // scan an interleaved mcu... process scan_n components in order\n               for (k=0; k < z->scan_n; ++k) {\n                  int n = z->order[k];\n                  // scan out an mcu's worth of this component; that's just determined\n                  // by the basic H and V specified for the component\n                  for (y=0; y < z->img_comp[n].v; ++y) {\n                     for (x=0; x < z->img_comp[n].h; ++x) {\n                        int x2 = (i*z->img_comp[n].h + x)*8;\n                        int y2 = (j*z->img_comp[n].v + y)*8;\n                        int ha = z->img_comp[n].ha;\n                        if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;\n                        z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);\n                     }\n                  }\n               }\n               // after all interleaved components, that's an interleaved MCU,\n               // so now count down the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      }\n   } else {\n      if (z->scan_n == 1) {\n         int i,j;\n         int n = z->order[0];\n         // non-interleaved data, we just need to process one block at a time,\n         // in trivial scanline order\n         // number of blocks to do just depends on how many actual \"pixels\" this\n         // component has, independent of interleaved MCU blocking and such\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);\n               if (z->spec_start == 0) {\n                  if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))\n                     return 0;\n               } else {\n                  int ha = z->img_comp[n].ha;\n                  if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))\n                     return 0;\n               }\n               // every data block is an MCU, so countdown the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      } else { // interleaved\n         int i,j,k,x,y;\n         for (j=0; j < z->img_mcu_y; ++j) {\n            for (i=0; i < z->img_mcu_x; ++i) {\n               // scan an interleaved mcu... process scan_n components in order\n               for (k=0; k < z->scan_n; ++k) {\n                  int n = z->order[k];\n                  // scan out an mcu's worth of this component; that's just determined\n                  // by the basic H and V specified for the component\n                  for (y=0; y < z->img_comp[n].v; ++y) {\n                     for (x=0; x < z->img_comp[n].h; ++x) {\n                        int x2 = (i*z->img_comp[n].h + x);\n                        int y2 = (j*z->img_comp[n].v + y);\n                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);\n                        if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))\n                           return 0;\n                     }\n                  }\n               }\n               // after all interleaved components, that's an interleaved MCU,\n               // so now count down the restart interval\n               if (--z->todo <= 0) {\n                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);\n                  if (!STBI__RESTART(z->marker)) return 1;\n                  stbi__jpeg_reset(z);\n               }\n            }\n         }\n         return 1;\n      }\n   }\n}\n\nstatic void stbi__jpeg_dequantize(short *data, stbi_uc *dequant)\n{\n   int i;\n   for (i=0; i < 64; ++i)\n      data[i] *= dequant[i];\n}\n\nstatic void stbi__jpeg_finish(stbi__jpeg *z)\n{\n   if (z->progressive) {\n      // dequantize and idct the data\n      int i,j,n;\n      for (n=0; n < z->s->img_n; ++n) {\n         int w = (z->img_comp[n].x+7) >> 3;\n         int h = (z->img_comp[n].y+7) >> 3;\n         for (j=0; j < h; ++j) {\n            for (i=0; i < w; ++i) {\n               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);\n               stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);\n               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);\n            }\n         }\n      }\n   }\n}\n\nstatic int stbi__process_marker(stbi__jpeg *z, int m)\n{\n   int L;\n   switch (m) {\n      case STBI__MARKER_none: // no marker found\n         return stbi__err(\"expected marker\",\"Corrupt JPEG\");\n\n      case 0xDD: // DRI - specify restart interval\n         if (stbi__get16be(z->s) != 4) return stbi__err(\"bad DRI len\",\"Corrupt JPEG\");\n         z->restart_interval = stbi__get16be(z->s);\n         return 1;\n\n      case 0xDB: // DQT - define quantization table\n         L = stbi__get16be(z->s)-2;\n         while (L > 0) {\n            int q = stbi__get8(z->s);\n            int p = q >> 4;\n            int t = q & 15,i;\n            if (p != 0) return stbi__err(\"bad DQT type\",\"Corrupt JPEG\");\n            if (t > 3) return stbi__err(\"bad DQT table\",\"Corrupt JPEG\");\n            for (i=0; i < 64; ++i)\n               z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s);\n            L -= 65;\n         }\n         return L==0;\n\n      case 0xC4: // DHT - define huffman table\n         L = stbi__get16be(z->s)-2;\n         while (L > 0) {\n            stbi_uc *v;\n            int sizes[16],i,n=0;\n            int q = stbi__get8(z->s);\n            int tc = q >> 4;\n            int th = q & 15;\n            if (tc > 1 || th > 3) return stbi__err(\"bad DHT header\",\"Corrupt JPEG\");\n            for (i=0; i < 16; ++i) {\n               sizes[i] = stbi__get8(z->s);\n               n += sizes[i];\n            }\n            L -= 17;\n            if (tc == 0) {\n               if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;\n               v = z->huff_dc[th].values;\n            } else {\n               if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;\n               v = z->huff_ac[th].values;\n            }\n            for (i=0; i < n; ++i)\n               v[i] = stbi__get8(z->s);\n            if (tc != 0)\n               stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);\n            L -= n;\n         }\n         return L==0;\n   }\n   // check for comment block or APP blocks\n   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {\n      stbi__skip(z->s, stbi__get16be(z->s)-2);\n      return 1;\n   }\n   return 0;\n}\n\n// after we see SOS\nstatic int stbi__process_scan_header(stbi__jpeg *z)\n{\n   int i;\n   int Ls = stbi__get16be(z->s);\n   z->scan_n = stbi__get8(z->s);\n   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err(\"bad SOS component count\",\"Corrupt JPEG\");\n   if (Ls != 6+2*z->scan_n) return stbi__err(\"bad SOS len\",\"Corrupt JPEG\");\n   for (i=0; i < z->scan_n; ++i) {\n      int id = stbi__get8(z->s), which;\n      int q = stbi__get8(z->s);\n      for (which = 0; which < z->s->img_n; ++which)\n         if (z->img_comp[which].id == id)\n            break;\n      if (which == z->s->img_n) return 0; // no match\n      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3) return stbi__err(\"bad DC huff\",\"Corrupt JPEG\");\n      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3) return stbi__err(\"bad AC huff\",\"Corrupt JPEG\");\n      z->order[i] = which;\n   }\n\n   {\n      int aa;\n      z->spec_start = stbi__get8(z->s);\n      z->spec_end   = stbi__get8(z->s); // should be 63, but might be 0\n      aa = stbi__get8(z->s);\n      z->succ_high = (aa >> 4);\n      z->succ_low  = (aa & 15);\n      if (z->progressive) {\n         if (z->spec_start > 63 || z->spec_end > 63  || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)\n            return stbi__err(\"bad SOS\", \"Corrupt JPEG\");\n      } else {\n         if (z->spec_start != 0) return stbi__err(\"bad SOS\",\"Corrupt JPEG\");\n         if (z->succ_high != 0 || z->succ_low != 0) return stbi__err(\"bad SOS\",\"Corrupt JPEG\");\n         z->spec_end = 63;\n      }\n   }\n\n   return 1;\n}\n\nstatic int stbi__process_frame_header(stbi__jpeg *z, int scan)\n{\n   stbi__context *s = z->s;\n   int Lf,p,i,q, h_max=1,v_max=1,c;\n   Lf = stbi__get16be(s);         if (Lf < 11) return stbi__err(\"bad SOF len\",\"Corrupt JPEG\"); // JPEG\n   p  = stbi__get8(s);            if (p != 8) return stbi__err(\"only 8-bit\",\"JPEG format not supported: 8-bit only\"); // JPEG baseline\n   s->img_y = stbi__get16be(s);   if (s->img_y == 0) return stbi__err(\"no header height\", \"JPEG format not supported: delayed height\"); // Legal, but we don't handle it--but neither does IJG\n   s->img_x = stbi__get16be(s);   if (s->img_x == 0) return stbi__err(\"0 width\",\"Corrupt JPEG\"); // JPEG requires\n   c = stbi__get8(s);\n   if (c != 3 && c != 1) return stbi__err(\"bad component count\",\"Corrupt JPEG\");    // JFIF requires\n   s->img_n = c;\n   for (i=0; i < c; ++i) {\n      z->img_comp[i].data = NULL;\n      z->img_comp[i].linebuf = NULL;\n   }\n\n   if (Lf != 8+3*s->img_n) return stbi__err(\"bad SOF len\",\"Corrupt JPEG\");\n\n   for (i=0; i < s->img_n; ++i) {\n      z->img_comp[i].id = stbi__get8(s);\n      if (z->img_comp[i].id != i+1)   // JFIF requires\n         if (z->img_comp[i].id != i)  // some version of jpegtran outputs non-JFIF-compliant files!\n            return stbi__err(\"bad component ID\",\"Corrupt JPEG\");\n      q = stbi__get8(s);\n      z->img_comp[i].h = (q >> 4);  if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err(\"bad H\",\"Corrupt JPEG\");\n      z->img_comp[i].v = q & 15;    if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err(\"bad V\",\"Corrupt JPEG\");\n      z->img_comp[i].tq = stbi__get8(s);  if (z->img_comp[i].tq > 3) return stbi__err(\"bad TQ\",\"Corrupt JPEG\");\n   }\n\n   if (scan != STBI__SCAN_load) return 1;\n\n   if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err(\"too large\", \"Image too large to decode\");\n\n   for (i=0; i < s->img_n; ++i) {\n      if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;\n      if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;\n   }\n\n   // compute interleaved mcu info\n   z->img_h_max = h_max;\n   z->img_v_max = v_max;\n   z->img_mcu_w = h_max * 8;\n   z->img_mcu_h = v_max * 8;\n   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;\n   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;\n\n   for (i=0; i < s->img_n; ++i) {\n      // number of effective pixels (e.g. for non-interleaved MCU)\n      z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;\n      z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;\n      // to simplify generation, we'll allocate enough memory to decode\n      // the bogus oversized data from using interleaved MCUs and their\n      // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't\n      // discard the extra data until colorspace conversion\n      z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;\n      z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;\n      z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15);\n\n      if (z->img_comp[i].raw_data == NULL) {\n         for(--i; i >= 0; --i) {\n            STBI_FREE(z->img_comp[i].raw_data);\n            z->img_comp[i].raw_data = NULL;\n         }\n         return stbi__err(\"outofmem\", \"Out of memory\");\n      }\n      // align blocks for idct using mmx/sse\n      z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);\n      z->img_comp[i].linebuf = NULL;\n      if (z->progressive) {\n         z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3;\n         z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3;\n         z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15);\n         z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);\n      } else {\n         z->img_comp[i].coeff = 0;\n         z->img_comp[i].raw_coeff = 0;\n      }\n   }\n\n   return 1;\n}\n\n// use comparisons since in some cases we handle more than one case (e.g. SOF)\n#define stbi__DNL(x)         ((x) == 0xdc)\n#define stbi__SOI(x)         ((x) == 0xd8)\n#define stbi__EOI(x)         ((x) == 0xd9)\n#define stbi__SOF(x)         ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)\n#define stbi__SOS(x)         ((x) == 0xda)\n\n#define stbi__SOF_progressive(x)   ((x) == 0xc2)\n\nstatic int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)\n{\n   int m;\n   z->marker = STBI__MARKER_none; // initialize cached marker to empty\n   m = stbi__get_marker(z);\n   if (!stbi__SOI(m)) return stbi__err(\"no SOI\",\"Corrupt JPEG\");\n   if (scan == STBI__SCAN_type) return 1;\n   m = stbi__get_marker(z);\n   while (!stbi__SOF(m)) {\n      if (!stbi__process_marker(z,m)) return 0;\n      m = stbi__get_marker(z);\n      while (m == STBI__MARKER_none) {\n         // some files have extra padding after their blocks, so ok, we'll scan\n         if (stbi__at_eof(z->s)) return stbi__err(\"no SOF\", \"Corrupt JPEG\");\n         m = stbi__get_marker(z);\n      }\n   }\n   z->progressive = stbi__SOF_progressive(m);\n   if (!stbi__process_frame_header(z, scan)) return 0;\n   return 1;\n}\n\n// decode image to YCbCr format\nstatic int stbi__decode_jpeg_image(stbi__jpeg *j)\n{\n   int m;\n   for (m = 0; m < 4; m++) {\n      j->img_comp[m].raw_data = NULL;\n      j->img_comp[m].raw_coeff = NULL;\n   }\n   j->restart_interval = 0;\n   if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;\n   m = stbi__get_marker(j);\n   while (!stbi__EOI(m)) {\n      if (stbi__SOS(m)) {\n         if (!stbi__process_scan_header(j)) return 0;\n         if (!stbi__parse_entropy_coded_data(j)) return 0;\n         if (j->marker == STBI__MARKER_none ) {\n            // handle 0s at the end of image data from IP Kamera 9060\n            while (!stbi__at_eof(j->s)) {\n               int x = stbi__get8(j->s);\n               if (x == 255) {\n                  j->marker = stbi__get8(j->s);\n                  break;\n               } else if (x != 0) {\n                  return stbi__err(\"junk before marker\", \"Corrupt JPEG\");\n               }\n            }\n            // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0\n         }\n      } else {\n         if (!stbi__process_marker(j, m)) return 0;\n      }\n      m = stbi__get_marker(j);\n   }\n   if (j->progressive)\n      stbi__jpeg_finish(j);\n   return 1;\n}\n\n// static jfif-centered resampling (across block boundaries)\n\ntypedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,\n                                    int w, int hs);\n\n#define stbi__div4(x) ((stbi_uc) ((x) >> 2))\n\nstatic stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   STBI_NOTUSED(out);\n   STBI_NOTUSED(in_far);\n   STBI_NOTUSED(w);\n   STBI_NOTUSED(hs);\n   return in_near;\n}\n\nstatic stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate two samples vertically for every one in input\n   int i;\n   STBI_NOTUSED(hs);\n   for (i=0; i < w; ++i)\n      out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);\n   return out;\n}\n\nstatic stbi_uc*  stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate two samples horizontally for every one in input\n   int i;\n   stbi_uc *input = in_near;\n\n   if (w == 1) {\n      // if only one sample, can't do any interpolation\n      out[0] = out[1] = input[0];\n      return out;\n   }\n\n   out[0] = input[0];\n   out[1] = stbi__div4(input[0]*3 + input[1] + 2);\n   for (i=1; i < w-1; ++i) {\n      int n = 3*input[i]+2;\n      out[i*2+0] = stbi__div4(n+input[i-1]);\n      out[i*2+1] = stbi__div4(n+input[i+1]);\n   }\n   out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);\n   out[i*2+1] = input[w-1];\n\n   STBI_NOTUSED(in_far);\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n\n#define stbi__div16(x) ((stbi_uc) ((x) >> 4))\n\nstatic stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate 2x2 samples for every one in input\n   int i,t0,t1;\n   if (w == 1) {\n      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);\n      return out;\n   }\n\n   t1 = 3*in_near[0] + in_far[0];\n   out[0] = stbi__div4(t1+2);\n   for (i=1; i < w; ++i) {\n      t0 = t1;\n      t1 = 3*in_near[i]+in_far[i];\n      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);\n      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);\n   }\n   out[w*2-1] = stbi__div4(t1+2);\n\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n\n#if defined(STBI_SSE2) || defined(STBI_NEON)\nstatic stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // need to generate 2x2 samples for every one in input\n   int i=0,t0,t1;\n\n   if (w == 1) {\n      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);\n      return out;\n   }\n\n   t1 = 3*in_near[0] + in_far[0];\n   // process groups of 8 pixels for as long as we can.\n   // note we can't handle the last pixel in a row in this loop\n   // because we need to handle the filter boundary conditions.\n   for (; i < ((w-1) & ~7); i += 8) {\n#if defined(STBI_SSE2)\n      // load and perform the vertical filtering pass\n      // this uses 3*x + y = 4*x + (y - x)\n      __m128i zero  = _mm_setzero_si128();\n      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));\n      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));\n      __m128i farw  = _mm_unpacklo_epi8(farb, zero);\n      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);\n      __m128i diff  = _mm_sub_epi16(farw, nearw);\n      __m128i nears = _mm_slli_epi16(nearw, 2);\n      __m128i curr  = _mm_add_epi16(nears, diff); // current row\n\n      // horizontal filter works the same based on shifted vers of current\n      // row. \"prev\" is current row shifted right by 1 pixel; we need to\n      // insert the previous pixel value (from t1).\n      // \"next\" is current row shifted left by 1 pixel, with first pixel\n      // of next block of 8 pixels added in.\n      __m128i prv0 = _mm_slli_si128(curr, 2);\n      __m128i nxt0 = _mm_srli_si128(curr, 2);\n      __m128i prev = _mm_insert_epi16(prv0, t1, 0);\n      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);\n\n      // horizontal filter, polyphase implementation since it's convenient:\n      // even pixels = 3*cur + prev = cur*4 + (prev - cur)\n      // odd  pixels = 3*cur + next = cur*4 + (next - cur)\n      // note the shared term.\n      __m128i bias  = _mm_set1_epi16(8);\n      __m128i curs = _mm_slli_epi16(curr, 2);\n      __m128i prvd = _mm_sub_epi16(prev, curr);\n      __m128i nxtd = _mm_sub_epi16(next, curr);\n      __m128i curb = _mm_add_epi16(curs, bias);\n      __m128i even = _mm_add_epi16(prvd, curb);\n      __m128i odd  = _mm_add_epi16(nxtd, curb);\n\n      // interleave even and odd pixels, then undo scaling.\n      __m128i int0 = _mm_unpacklo_epi16(even, odd);\n      __m128i int1 = _mm_unpackhi_epi16(even, odd);\n      __m128i de0  = _mm_srli_epi16(int0, 4);\n      __m128i de1  = _mm_srli_epi16(int1, 4);\n\n      // pack and write output\n      __m128i outv = _mm_packus_epi16(de0, de1);\n      _mm_storeu_si128((__m128i *) (out + i*2), outv);\n#elif defined(STBI_NEON)\n      // load and perform the vertical filtering pass\n      // this uses 3*x + y = 4*x + (y - x)\n      uint8x8_t farb  = vld1_u8(in_far + i);\n      uint8x8_t nearb = vld1_u8(in_near + i);\n      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));\n      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));\n      int16x8_t curr  = vaddq_s16(nears, diff); // current row\n\n      // horizontal filter works the same based on shifted vers of current\n      // row. \"prev\" is current row shifted right by 1 pixel; we need to\n      // insert the previous pixel value (from t1).\n      // \"next\" is current row shifted left by 1 pixel, with first pixel\n      // of next block of 8 pixels added in.\n      int16x8_t prv0 = vextq_s16(curr, curr, 7);\n      int16x8_t nxt0 = vextq_s16(curr, curr, 1);\n      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);\n      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);\n\n      // horizontal filter, polyphase implementation since it's convenient:\n      // even pixels = 3*cur + prev = cur*4 + (prev - cur)\n      // odd  pixels = 3*cur + next = cur*4 + (next - cur)\n      // note the shared term.\n      int16x8_t curs = vshlq_n_s16(curr, 2);\n      int16x8_t prvd = vsubq_s16(prev, curr);\n      int16x8_t nxtd = vsubq_s16(next, curr);\n      int16x8_t even = vaddq_s16(curs, prvd);\n      int16x8_t odd  = vaddq_s16(curs, nxtd);\n\n      // undo scaling and round, then store with even/odd phases interleaved\n      uint8x8x2_t o;\n      o.val[0] = vqrshrun_n_s16(even, 4);\n      o.val[1] = vqrshrun_n_s16(odd,  4);\n      vst2_u8(out + i*2, o);\n#endif\n\n      // \"previous\" value for next iter\n      t1 = 3*in_near[i+7] + in_far[i+7];\n   }\n\n   t0 = t1;\n   t1 = 3*in_near[i] + in_far[i];\n   out[i*2] = stbi__div16(3*t1 + t0 + 8);\n\n   for (++i; i < w; ++i) {\n      t0 = t1;\n      t1 = 3*in_near[i]+in_far[i];\n      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);\n      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);\n   }\n   out[w*2-1] = stbi__div4(t1+2);\n\n   STBI_NOTUSED(hs);\n\n   return out;\n}\n#endif\n\nstatic stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)\n{\n   // resample with nearest-neighbor\n   int i,j;\n   STBI_NOTUSED(in_far);\n   for (i=0; i < w; ++i)\n      for (j=0; j < hs; ++j)\n         out[i*hs+j] = in_near[i];\n   return out;\n}\n\n#ifdef STBI_JPEG_OLD\n// this is the same YCbCr-to-RGB calculation that stb_image has used\n// historically before the algorithm changes in 1.49\n#define float2fixed(x)  ((int) ((x) * 65536 + 0.5))\nstatic void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)\n{\n   int i;\n   for (i=0; i < count; ++i) {\n      int y_fixed = (y[i] << 16) + 32768; // rounding\n      int r,g,b;\n      int cr = pcr[i] - 128;\n      int cb = pcb[i] - 128;\n      r = y_fixed + cr*float2fixed(1.40200f);\n      g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f);\n      b = y_fixed                            + cb*float2fixed(1.77200f);\n      r >>= 16;\n      g >>= 16;\n      b >>= 16;\n      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }\n      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }\n      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }\n      out[0] = (stbi_uc)r;\n      out[1] = (stbi_uc)g;\n      out[2] = (stbi_uc)b;\n      out[3] = 255;\n      out += step;\n   }\n}\n#else\n// this is a reduced-precision calculation of YCbCr-to-RGB introduced\n// to make sure the code produces the same results in both SIMD and scalar\n#define float2fixed(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)\nstatic void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)\n{\n   int i;\n   for (i=0; i < count; ++i) {\n      int y_fixed = (y[i] << 20) + (1<<19); // rounding\n      int r,g,b;\n      int cr = pcr[i] - 128;\n      int cb = pcb[i] - 128;\n      r = y_fixed +  cr* float2fixed(1.40200f);\n      g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000);\n      b = y_fixed                               +   cb* float2fixed(1.77200f);\n      r >>= 20;\n      g >>= 20;\n      b >>= 20;\n      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }\n      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }\n      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }\n      out[0] = (stbi_uc)r;\n      out[1] = (stbi_uc)g;\n      out[2] = (stbi_uc)b;\n      out[3] = 255;\n      out += step;\n   }\n}\n#endif\n\n#if defined(STBI_SSE2) || defined(STBI_NEON)\nstatic void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)\n{\n   int i = 0;\n\n#ifdef STBI_SSE2\n   // step == 3 is pretty ugly on the final interleave, and i'm not convinced\n   // it's useful in practice (you wouldn't use it for textures, for example).\n   // so just accelerate step == 4 case.\n   if (step == 4) {\n      // this is a fairly straightforward implementation and not super-optimized.\n      __m128i signflip  = _mm_set1_epi8(-0x80);\n      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));\n      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));\n      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));\n      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));\n      __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);\n      __m128i xw = _mm_set1_epi16(255); // alpha channel\n\n      for (; i+7 < count; i += 8) {\n         // load\n         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));\n         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));\n         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));\n         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128\n         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128\n\n         // unpack to short (and left-shift cr, cb by 8)\n         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);\n         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);\n         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);\n\n         // color transform\n         __m128i yws = _mm_srli_epi16(yw, 4);\n         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);\n         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);\n         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);\n         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);\n         __m128i rws = _mm_add_epi16(cr0, yws);\n         __m128i gwt = _mm_add_epi16(cb0, yws);\n         __m128i bws = _mm_add_epi16(yws, cb1);\n         __m128i gws = _mm_add_epi16(gwt, cr1);\n\n         // descale\n         __m128i rw = _mm_srai_epi16(rws, 4);\n         __m128i bw = _mm_srai_epi16(bws, 4);\n         __m128i gw = _mm_srai_epi16(gws, 4);\n\n         // back to byte, set up for transpose\n         __m128i brb = _mm_packus_epi16(rw, bw);\n         __m128i gxb = _mm_packus_epi16(gw, xw);\n\n         // transpose to interleave channels\n         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);\n         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);\n         __m128i o0 = _mm_unpacklo_epi16(t0, t1);\n         __m128i o1 = _mm_unpackhi_epi16(t0, t1);\n\n         // store\n         _mm_storeu_si128((__m128i *) (out + 0), o0);\n         _mm_storeu_si128((__m128i *) (out + 16), o1);\n         out += 32;\n      }\n   }\n#endif\n\n#ifdef STBI_NEON\n   // in this version, step=3 support would be easy to add. but is there demand?\n   if (step == 4) {\n      // this is a fairly straightforward implementation and not super-optimized.\n      uint8x8_t signflip = vdup_n_u8(0x80);\n      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));\n      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));\n      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));\n      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));\n\n      for (; i+7 < count; i += 8) {\n         // load\n         uint8x8_t y_bytes  = vld1_u8(y + i);\n         uint8x8_t cr_bytes = vld1_u8(pcr + i);\n         uint8x8_t cb_bytes = vld1_u8(pcb + i);\n         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));\n         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));\n\n         // expand to s16\n         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));\n         int16x8_t crw = vshll_n_s8(cr_biased, 7);\n         int16x8_t cbw = vshll_n_s8(cb_biased, 7);\n\n         // color transform\n         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);\n         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);\n         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);\n         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);\n         int16x8_t rws = vaddq_s16(yws, cr0);\n         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);\n         int16x8_t bws = vaddq_s16(yws, cb1);\n\n         // undo scaling, round, convert to byte\n         uint8x8x4_t o;\n         o.val[0] = vqrshrun_n_s16(rws, 4);\n         o.val[1] = vqrshrun_n_s16(gws, 4);\n         o.val[2] = vqrshrun_n_s16(bws, 4);\n         o.val[3] = vdup_n_u8(255);\n\n         // store, interleaving r/g/b/a\n         vst4_u8(out, o);\n         out += 8*4;\n      }\n   }\n#endif\n\n   for (; i < count; ++i) {\n      int y_fixed = (y[i] << 20) + (1<<19); // rounding\n      int r,g,b;\n      int cr = pcr[i] - 128;\n      int cb = pcb[i] - 128;\n      r = y_fixed + cr* float2fixed(1.40200f);\n      g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000);\n      b = y_fixed                             +   cb* float2fixed(1.77200f);\n      r >>= 20;\n      g >>= 20;\n      b >>= 20;\n      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }\n      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }\n      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }\n      out[0] = (stbi_uc)r;\n      out[1] = (stbi_uc)g;\n      out[2] = (stbi_uc)b;\n      out[3] = 255;\n      out += step;\n   }\n}\n#endif\n\n// set up the kernels\nstatic void stbi__setup_jpeg(stbi__jpeg *j)\n{\n   j->idct_block_kernel = stbi__idct_block;\n   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;\n   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;\n\n#ifdef STBI_SSE2\n   if (stbi__sse2_available()) {\n      j->idct_block_kernel = stbi__idct_simd;\n      #ifndef STBI_JPEG_OLD\n      j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;\n      #endif\n      j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;\n   }\n#endif\n\n#ifdef STBI_NEON\n   j->idct_block_kernel = stbi__idct_simd;\n   #ifndef STBI_JPEG_OLD\n   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;\n   #endif\n   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;\n#endif\n}\n\n// clean up the temporary component buffers\nstatic void stbi__cleanup_jpeg(stbi__jpeg *j)\n{\n   int i;\n   for (i=0; i < j->s->img_n; ++i) {\n      if (j->img_comp[i].raw_data) {\n         STBI_FREE(j->img_comp[i].raw_data);\n         j->img_comp[i].raw_data = NULL;\n         j->img_comp[i].data = NULL;\n      }\n      if (j->img_comp[i].raw_coeff) {\n         STBI_FREE(j->img_comp[i].raw_coeff);\n         j->img_comp[i].raw_coeff = 0;\n         j->img_comp[i].coeff = 0;\n      }\n      if (j->img_comp[i].linebuf) {\n         STBI_FREE(j->img_comp[i].linebuf);\n         j->img_comp[i].linebuf = NULL;\n      }\n   }\n}\n\ntypedef struct\n{\n   resample_row_func resample;\n   stbi_uc *line0,*line1;\n   int hs,vs;   // expansion factor in each axis\n   int w_lores; // horizontal pixels pre-expansion\n   int ystep;   // how far through vertical expansion we are\n   int ypos;    // which pre-expansion row we're on\n} stbi__resample;\n\nstatic stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)\n{\n   int n, decode_n;\n   z->s->img_n = 0; // make stbi__cleanup_jpeg safe\n\n   // validate req_comp\n   if (req_comp < 0 || req_comp > 4) return stbi__errpuc(\"bad req_comp\", \"Internal error\");\n\n   // load a jpeg image from whichever source, but leave in YCbCr format\n   if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }\n\n   // determine actual number of components to generate\n   n = req_comp ? req_comp : z->s->img_n;\n\n   if (z->s->img_n == 3 && n < 3)\n      decode_n = 1;\n   else\n      decode_n = z->s->img_n;\n\n   // resample and color-convert\n   {\n      int k;\n      unsigned int i,j;\n      stbi_uc *output;\n      stbi_uc *coutput[4];\n\n      stbi__resample res_comp[4];\n\n      for (k=0; k < decode_n; ++k) {\n         stbi__resample *r = &res_comp[k];\n\n         // allocate line buffer big enough for upsampling off the edges\n         // with upsample factor of 4\n         z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);\n         if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n\n         r->hs      = z->img_h_max / z->img_comp[k].h;\n         r->vs      = z->img_v_max / z->img_comp[k].v;\n         r->ystep   = r->vs >> 1;\n         r->w_lores = (z->s->img_x + r->hs-1) / r->hs;\n         r->ypos    = 0;\n         r->line0   = r->line1 = z->img_comp[k].data;\n\n         if      (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;\n         else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;\n         else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;\n         else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;\n         else                               r->resample = stbi__resample_row_generic;\n      }\n\n      // can't error after this so, this is safe\n      output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1);\n      if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc(\"outofmem\", \"Out of memory\"); }\n\n      // now go ahead and resample\n      for (j=0; j < z->s->img_y; ++j) {\n         stbi_uc *out = output + n * z->s->img_x * j;\n         for (k=0; k < decode_n; ++k) {\n            stbi__resample *r = &res_comp[k];\n            int y_bot = r->ystep >= (r->vs >> 1);\n            coutput[k] = r->resample(z->img_comp[k].linebuf,\n                                     y_bot ? r->line1 : r->line0,\n                                     y_bot ? r->line0 : r->line1,\n                                     r->w_lores, r->hs);\n            if (++r->ystep >= r->vs) {\n               r->ystep = 0;\n               r->line0 = r->line1;\n               if (++r->ypos < z->img_comp[k].y)\n                  r->line1 += z->img_comp[k].w2;\n            }\n         }\n         if (n >= 3) {\n            stbi_uc *y = coutput[0];\n            if (z->s->img_n == 3) {\n               z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);\n            } else\n               for (i=0; i < z->s->img_x; ++i) {\n                  out[0] = out[1] = out[2] = y[i];\n                  out[3] = 255; // not used if n==3\n                  out += n;\n               }\n         } else {\n            stbi_uc *y = coutput[0];\n            if (n == 1)\n               for (i=0; i < z->s->img_x; ++i) out[i] = y[i];\n            else\n               for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255;\n         }\n      }\n      stbi__cleanup_jpeg(z);\n      *out_x = z->s->img_x;\n      *out_y = z->s->img_y;\n      if (comp) *comp  = z->s->img_n; // report original components, not output\n      return output;\n   }\n}\n\nstatic unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__jpeg j;\n   j.s = s;\n   stbi__setup_jpeg(&j);\n   return load_jpeg_image(&j, x,y,comp,req_comp);\n}\n\nstatic int stbi__jpeg_test(stbi__context *s)\n{\n   int r;\n   stbi__jpeg j;\n   j.s = s;\n   stbi__setup_jpeg(&j);\n   r = stbi__decode_jpeg_header(&j, STBI__SCAN_type);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)\n{\n   if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {\n      stbi__rewind( j->s );\n      return 0;\n   }\n   if (x) *x = j->s->img_x;\n   if (y) *y = j->s->img_y;\n   if (comp) *comp = j->s->img_n;\n   return 1;\n}\n\nstatic int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   stbi__jpeg j;\n   j.s = s;\n   return stbi__jpeg_info_raw(&j, x, y, comp);\n}\n#endif\n\n// public domain zlib decode    v0.2  Sean Barrett 2006-11-18\n//    simple implementation\n//      - all input must be provided in an upfront buffer\n//      - all output is written to a single output buffer (can malloc/realloc)\n//    performance\n//      - fast huffman\n\n#ifndef STBI_NO_ZLIB\n\n// fast-way is faster to check than jpeg huffman, but slow way is slower\n#define STBI__ZFAST_BITS  9 // accelerate all cases in default tables\n#define STBI__ZFAST_MASK  ((1 << STBI__ZFAST_BITS) - 1)\n\n// zlib-style huffman encoding\n// (jpegs packs from left, zlib from right, so can't share code)\ntypedef struct\n{\n   stbi__uint16 fast[1 << STBI__ZFAST_BITS];\n   stbi__uint16 firstcode[16];\n   int maxcode[17];\n   stbi__uint16 firstsymbol[16];\n   stbi_uc  size[288];\n   stbi__uint16 value[288];\n} stbi__zhuffman;\n\nstbi_inline static int stbi__bitreverse16(int n)\n{\n  n = ((n & 0xAAAA) >>  1) | ((n & 0x5555) << 1);\n  n = ((n & 0xCCCC) >>  2) | ((n & 0x3333) << 2);\n  n = ((n & 0xF0F0) >>  4) | ((n & 0x0F0F) << 4);\n  n = ((n & 0xFF00) >>  8) | ((n & 0x00FF) << 8);\n  return n;\n}\n\nstbi_inline static int stbi__bit_reverse(int v, int bits)\n{\n   STBI_ASSERT(bits <= 16);\n   // to bit reverse n bits, reverse 16 and shift\n   // e.g. 11 bits, bit reverse and shift away 5\n   return stbi__bitreverse16(v) >> (16-bits);\n}\n\nstatic int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)\n{\n   int i,k=0;\n   int code, next_code[16], sizes[17];\n\n   // DEFLATE spec for generating codes\n   memset(sizes, 0, sizeof(sizes));\n   memset(z->fast, 0, sizeof(z->fast));\n   for (i=0; i < num; ++i)\n      ++sizes[sizelist[i]];\n   sizes[0] = 0;\n   for (i=1; i < 16; ++i)\n      if (sizes[i] > (1 << i))\n         return stbi__err(\"bad sizes\", \"Corrupt PNG\");\n   code = 0;\n   for (i=1; i < 16; ++i) {\n      next_code[i] = code;\n      z->firstcode[i] = (stbi__uint16) code;\n      z->firstsymbol[i] = (stbi__uint16) k;\n      code = (code + sizes[i]);\n      if (sizes[i])\n         if (code-1 >= (1 << i)) return stbi__err(\"bad codelengths\",\"Corrupt PNG\");\n      z->maxcode[i] = code << (16-i); // preshift for inner loop\n      code <<= 1;\n      k += sizes[i];\n   }\n   z->maxcode[16] = 0x10000; // sentinel\n   for (i=0; i < num; ++i) {\n      int s = sizelist[i];\n      if (s) {\n         int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];\n         stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);\n         z->size [c] = (stbi_uc     ) s;\n         z->value[c] = (stbi__uint16) i;\n         if (s <= STBI__ZFAST_BITS) {\n            int j = stbi__bit_reverse(next_code[s],s);\n            while (j < (1 << STBI__ZFAST_BITS)) {\n               z->fast[j] = fastv;\n               j += (1 << s);\n            }\n         }\n         ++next_code[s];\n      }\n   }\n   return 1;\n}\n\n// zlib-from-memory implementation for PNG reading\n//    because PNG allows splitting the zlib stream arbitrarily,\n//    and it's annoying structurally to have PNG call ZLIB call PNG,\n//    we require PNG read all the IDATs and combine them into a single\n//    memory buffer\n\ntypedef struct\n{\n   stbi_uc *zbuffer, *zbuffer_end;\n   int num_bits;\n   stbi__uint32 code_buffer;\n\n   char *zout;\n   char *zout_start;\n   char *zout_end;\n   int   z_expandable;\n\n   stbi__zhuffman z_length, z_distance;\n} stbi__zbuf;\n\nstbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)\n{\n   if (z->zbuffer >= z->zbuffer_end) return 0;\n   return *z->zbuffer++;\n}\n\nstatic void stbi__fill_bits(stbi__zbuf *z)\n{\n   do {\n      STBI_ASSERT(z->code_buffer < (1U << z->num_bits));\n      z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;\n      z->num_bits += 8;\n   } while (z->num_bits <= 24);\n}\n\nstbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)\n{\n   unsigned int k;\n   if (z->num_bits < n) stbi__fill_bits(z);\n   k = z->code_buffer & ((1 << n) - 1);\n   z->code_buffer >>= n;\n   z->num_bits -= n;\n   return k;\n}\n\nstatic int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)\n{\n   int b,s,k;\n   // not resolved by fast table, so compute it the slow way\n   // use jpeg approach, which requires MSbits at top\n   k = stbi__bit_reverse(a->code_buffer, 16);\n   for (s=STBI__ZFAST_BITS+1; ; ++s)\n      if (k < z->maxcode[s])\n         break;\n   if (s == 16) return -1; // invalid code!\n   // code size is s, so:\n   b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];\n   STBI_ASSERT(z->size[b] == s);\n   a->code_buffer >>= s;\n   a->num_bits -= s;\n   return z->value[b];\n}\n\nstbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)\n{\n   int b,s;\n   if (a->num_bits < 16) stbi__fill_bits(a);\n   b = z->fast[a->code_buffer & STBI__ZFAST_MASK];\n   if (b) {\n      s = b >> 9;\n      a->code_buffer >>= s;\n      a->num_bits -= s;\n      return b & 511;\n   }\n   return stbi__zhuffman_decode_slowpath(a, z);\n}\n\nstatic int stbi__zexpand(stbi__zbuf *z, char *zout, int n)  // need to make room for n bytes\n{\n   char *q;\n   int cur, limit;\n   z->zout = zout;\n   if (!z->z_expandable) return stbi__err(\"output buffer limit\",\"Corrupt PNG\");\n   cur   = (int) (z->zout     - z->zout_start);\n   limit = (int) (z->zout_end - z->zout_start);\n   while (cur + n > limit)\n      limit *= 2;\n   q = (char *) STBI_REALLOC(z->zout_start, limit);\n   if (q == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n   z->zout_start = q;\n   z->zout       = q + cur;\n   z->zout_end   = q + limit;\n   return 1;\n}\n\nstatic int stbi__zlength_base[31] = {\n   3,4,5,6,7,8,9,10,11,13,\n   15,17,19,23,27,31,35,43,51,59,\n   67,83,99,115,131,163,195,227,258,0,0 };\n\nstatic int stbi__zlength_extra[31]=\n{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };\n\nstatic int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,\n257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};\n\nstatic int stbi__zdist_extra[32] =\n{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};\n\nstatic int stbi__parse_huffman_block(stbi__zbuf *a)\n{\n   char *zout = a->zout;\n   for(;;) {\n      int z = stbi__zhuffman_decode(a, &a->z_length);\n      if (z < 256) {\n         if (z < 0) return stbi__err(\"bad huffman code\",\"Corrupt PNG\"); // error in huffman codes\n         if (zout >= a->zout_end) {\n            if (!stbi__zexpand(a, zout, 1)) return 0;\n            zout = a->zout;\n         }\n         *zout++ = (char) z;\n      } else {\n         stbi_uc *p;\n         int len,dist;\n         if (z == 256) {\n            a->zout = zout;\n            return 1;\n         }\n         z -= 257;\n         len = stbi__zlength_base[z];\n         if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);\n         z = stbi__zhuffman_decode(a, &a->z_distance);\n         if (z < 0) return stbi__err(\"bad huffman code\",\"Corrupt PNG\");\n         dist = stbi__zdist_base[z];\n         if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);\n         if (zout - a->zout_start < dist) return stbi__err(\"bad dist\",\"Corrupt PNG\");\n         if (zout + len > a->zout_end) {\n            if (!stbi__zexpand(a, zout, len)) return 0;\n            zout = a->zout;\n         }\n         p = (stbi_uc *) (zout - dist);\n         if (dist == 1) { // run of one byte; common in images.\n            stbi_uc v = *p;\n            if (len) { do *zout++ = v; while (--len); }\n         } else {\n            if (len) { do *zout++ = *p++; while (--len); }\n         }\n      }\n   }\n}\n\nstatic int stbi__compute_huffman_codes(stbi__zbuf *a)\n{\n   static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };\n   stbi__zhuffman z_codelength;\n   stbi_uc lencodes[286+32+137];//padding for maximum single op\n   stbi_uc codelength_sizes[19];\n   int i,n;\n\n   int hlit  = stbi__zreceive(a,5) + 257;\n   int hdist = stbi__zreceive(a,5) + 1;\n   int hclen = stbi__zreceive(a,4) + 4;\n\n   memset(codelength_sizes, 0, sizeof(codelength_sizes));\n   for (i=0; i < hclen; ++i) {\n      int s = stbi__zreceive(a,3);\n      codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;\n   }\n   if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;\n\n   n = 0;\n   while (n < hlit + hdist) {\n      int c = stbi__zhuffman_decode(a, &z_codelength);\n      if (c < 0 || c >= 19) return stbi__err(\"bad codelengths\", \"Corrupt PNG\");\n      if (c < 16)\n         lencodes[n++] = (stbi_uc) c;\n      else if (c == 16) {\n         c = stbi__zreceive(a,2)+3;\n         memset(lencodes+n, lencodes[n-1], c);\n         n += c;\n      } else if (c == 17) {\n         c = stbi__zreceive(a,3)+3;\n         memset(lencodes+n, 0, c);\n         n += c;\n      } else {\n         STBI_ASSERT(c == 18);\n         c = stbi__zreceive(a,7)+11;\n         memset(lencodes+n, 0, c);\n         n += c;\n      }\n   }\n   if (n != hlit+hdist) return stbi__err(\"bad codelengths\",\"Corrupt PNG\");\n   if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;\n   if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;\n   return 1;\n}\n\nstatic int stbi__parse_uncomperssed_block(stbi__zbuf *a)\n{\n   stbi_uc header[4];\n   int len,nlen,k;\n   if (a->num_bits & 7)\n      stbi__zreceive(a, a->num_bits & 7); // discard\n   // drain the bit-packed data into header\n   k = 0;\n   while (a->num_bits > 0) {\n      header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check\n      a->code_buffer >>= 8;\n      a->num_bits -= 8;\n   }\n   STBI_ASSERT(a->num_bits == 0);\n   // now fill header the normal way\n   while (k < 4)\n      header[k++] = stbi__zget8(a);\n   len  = header[1] * 256 + header[0];\n   nlen = header[3] * 256 + header[2];\n   if (nlen != (len ^ 0xffff)) return stbi__err(\"zlib corrupt\",\"Corrupt PNG\");\n   if (a->zbuffer + len > a->zbuffer_end) return stbi__err(\"read past buffer\",\"Corrupt PNG\");\n   if (a->zout + len > a->zout_end)\n      if (!stbi__zexpand(a, a->zout, len)) return 0;\n   memcpy(a->zout, a->zbuffer, len);\n   a->zbuffer += len;\n   a->zout += len;\n   return 1;\n}\n\nstatic int stbi__parse_zlib_header(stbi__zbuf *a)\n{\n   int cmf   = stbi__zget8(a);\n   int cm    = cmf & 15;\n   /* int cinfo = cmf >> 4; */\n   int flg   = stbi__zget8(a);\n   if ((cmf*256+flg) % 31 != 0) return stbi__err(\"bad zlib header\",\"Corrupt PNG\"); // zlib spec\n   if (flg & 32) return stbi__err(\"no preset dict\",\"Corrupt PNG\"); // preset dictionary not allowed in png\n   if (cm != 8) return stbi__err(\"bad compression\",\"Corrupt PNG\"); // DEFLATE required for png\n   // window = 1 << (8 + cinfo)... but who cares, we fully buffer output\n   return 1;\n}\n\n// @TODO: should statically initialize these for optimal thread safety\nstatic stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32];\nstatic void stbi__init_zdefaults(void)\n{\n   int i;   // use <= to match clearly with spec\n   for (i=0; i <= 143; ++i)     stbi__zdefault_length[i]   = 8;\n   for (   ; i <= 255; ++i)     stbi__zdefault_length[i]   = 9;\n   for (   ; i <= 279; ++i)     stbi__zdefault_length[i]   = 7;\n   for (   ; i <= 287; ++i)     stbi__zdefault_length[i]   = 8;\n\n   for (i=0; i <=  31; ++i)     stbi__zdefault_distance[i] = 5;\n}\n\nstatic int stbi__parse_zlib(stbi__zbuf *a, int parse_header)\n{\n   int final, type;\n   if (parse_header)\n      if (!stbi__parse_zlib_header(a)) return 0;\n   a->num_bits = 0;\n   a->code_buffer = 0;\n   do {\n      final = stbi__zreceive(a,1);\n      type = stbi__zreceive(a,2);\n      if (type == 0) {\n         if (!stbi__parse_uncomperssed_block(a)) return 0;\n      } else if (type == 3) {\n         return 0;\n      } else {\n         if (type == 1) {\n            // use fixed code lengths\n            if (!stbi__zdefault_distance[31]) stbi__init_zdefaults();\n            if (!stbi__zbuild_huffman(&a->z_length  , stbi__zdefault_length  , 288)) return 0;\n            if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance,  32)) return 0;\n         } else {\n            if (!stbi__compute_huffman_codes(a)) return 0;\n         }\n         if (!stbi__parse_huffman_block(a)) return 0;\n      }\n   } while (!final);\n   return 1;\n}\n\nstatic int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)\n{\n   a->zout_start = obuf;\n   a->zout       = obuf;\n   a->zout_end   = obuf + olen;\n   a->z_expandable = exp;\n\n   return stbi__parse_zlib(a, parse_header);\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(initial_size);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer + len;\n   if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)\n{\n   return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);\n}\n\nSTBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(initial_size);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer + len;\n   if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)\n{\n   stbi__zbuf a;\n   a.zbuffer = (stbi_uc *) ibuffer;\n   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;\n   if (stbi__do_zlib(&a, obuffer, olen, 0, 1))\n      return (int) (a.zout - a.zout_start);\n   else\n      return -1;\n}\n\nSTBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)\n{\n   stbi__zbuf a;\n   char *p = (char *) stbi__malloc(16384);\n   if (p == NULL) return NULL;\n   a.zbuffer = (stbi_uc *) buffer;\n   a.zbuffer_end = (stbi_uc *) buffer+len;\n   if (stbi__do_zlib(&a, p, 16384, 1, 0)) {\n      if (outlen) *outlen = (int) (a.zout - a.zout_start);\n      return a.zout_start;\n   } else {\n      STBI_FREE(a.zout_start);\n      return NULL;\n   }\n}\n\nSTBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)\n{\n   stbi__zbuf a;\n   a.zbuffer = (stbi_uc *) ibuffer;\n   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;\n   if (stbi__do_zlib(&a, obuffer, olen, 0, 0))\n      return (int) (a.zout - a.zout_start);\n   else\n      return -1;\n}\n#endif\n\n// public domain \"baseline\" PNG decoder   v0.10  Sean Barrett 2006-11-18\n//    simple implementation\n//      - only 8-bit samples\n//      - no CRC checking\n//      - allocates lots of intermediate memory\n//        - avoids problem of streaming data between subsystems\n//        - avoids explicit window management\n//    performance\n//      - uses stb_zlib, a PD zlib implementation with fast huffman decoding\n\n#ifndef STBI_NO_PNG\ntypedef struct\n{\n   stbi__uint32 length;\n   stbi__uint32 type;\n} stbi__pngchunk;\n\nstatic stbi__pngchunk stbi__get_chunk_header(stbi__context *s)\n{\n   stbi__pngchunk c;\n   c.length = stbi__get32be(s);\n   c.type   = stbi__get32be(s);\n   return c;\n}\n\nstatic int stbi__check_png_header(stbi__context *s)\n{\n   static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };\n   int i;\n   for (i=0; i < 8; ++i)\n      if (stbi__get8(s) != png_sig[i]) return stbi__err(\"bad png sig\",\"Not a PNG\");\n   return 1;\n}\n\ntypedef struct\n{\n   stbi__context *s;\n   stbi_uc *idata, *expanded, *out;\n} stbi__png;\n\n\nenum {\n   STBI__F_none=0,\n   STBI__F_sub=1,\n   STBI__F_up=2,\n   STBI__F_avg=3,\n   STBI__F_paeth=4,\n   // synthetic filters used for first scanline to avoid needing a dummy row of 0s\n   STBI__F_avg_first,\n   STBI__F_paeth_first\n};\n\nstatic stbi_uc first_row_filter[5] =\n{\n   STBI__F_none,\n   STBI__F_sub,\n   STBI__F_none,\n   STBI__F_avg_first,\n   STBI__F_paeth_first\n};\n\nstatic int stbi__paeth(int a, int b, int c)\n{\n   int p = a + b - c;\n   int pa = abs(p-a);\n   int pb = abs(p-b);\n   int pc = abs(p-c);\n   if (pa <= pb && pa <= pc) return a;\n   if (pb <= pc) return b;\n   return c;\n}\n\nstatic stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };\n\n// create the png data from post-deflated data\nstatic int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)\n{\n   stbi__context *s = a->s;\n   stbi__uint32 i,j,stride = x*out_n;\n   stbi__uint32 img_len, img_width_bytes;\n   int k;\n   int img_n = s->img_n; // copy it into a local for later\n\n   STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);\n   a->out = (stbi_uc *) stbi__malloc(x * y * out_n); // extra bytes to write off the end into\n   if (!a->out) return stbi__err(\"outofmem\", \"Out of memory\");\n\n   img_width_bytes = (((img_n * x * depth) + 7) >> 3);\n   img_len = (img_width_bytes + 1) * y;\n   if (s->img_x == x && s->img_y == y) {\n      if (raw_len != img_len) return stbi__err(\"not enough pixels\",\"Corrupt PNG\");\n   } else { // interlaced:\n      if (raw_len < img_len) return stbi__err(\"not enough pixels\",\"Corrupt PNG\");\n   }\n\n   for (j=0; j < y; ++j) {\n      stbi_uc *cur = a->out + stride*j;\n      stbi_uc *prior = cur - stride;\n      int filter = *raw++;\n      int filter_bytes = img_n;\n      int width = x;\n      if (filter > 4)\n         return stbi__err(\"invalid filter\",\"Corrupt PNG\");\n\n      if (depth < 8) {\n         STBI_ASSERT(img_width_bytes <= x);\n         cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place\n         filter_bytes = 1;\n         width = img_width_bytes;\n      }\n\n      // if first row, use special filter that doesn't sample previous row\n      if (j == 0) filter = first_row_filter[filter];\n\n      // handle first byte explicitly\n      for (k=0; k < filter_bytes; ++k) {\n         switch (filter) {\n            case STBI__F_none       : cur[k] = raw[k]; break;\n            case STBI__F_sub        : cur[k] = raw[k]; break;\n            case STBI__F_up         : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;\n            case STBI__F_avg        : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;\n            case STBI__F_paeth      : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;\n            case STBI__F_avg_first  : cur[k] = raw[k]; break;\n            case STBI__F_paeth_first: cur[k] = raw[k]; break;\n         }\n      }\n\n      if (depth == 8) {\n         if (img_n != out_n)\n            cur[img_n] = 255; // first pixel\n         raw += img_n;\n         cur += out_n;\n         prior += out_n;\n      } else {\n         raw += 1;\n         cur += 1;\n         prior += 1;\n      }\n\n      // this is a little gross, so that we don't switch per-pixel or per-component\n      if (depth < 8 || img_n == out_n) {\n         int nk = (width - 1)*img_n;\n         #define CASE(f) \\\n             case f:     \\\n                for (k=0; k < nk; ++k)\n         switch (filter) {\n            // \"none\" filter turns into a memcpy here; make that explicit.\n            case STBI__F_none:         memcpy(cur, raw, nk); break;\n            CASE(STBI__F_sub)          cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); break;\n            CASE(STBI__F_up)           cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;\n            CASE(STBI__F_avg)          cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); break;\n            CASE(STBI__F_paeth)        cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); break;\n            CASE(STBI__F_avg_first)    cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); break;\n            CASE(STBI__F_paeth_first)  cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); break;\n         }\n         #undef CASE\n         raw += nk;\n      } else {\n         STBI_ASSERT(img_n+1 == out_n);\n         #define CASE(f) \\\n             case f:     \\\n                for (i=x-1; i >= 1; --i, cur[img_n]=255,raw+=img_n,cur+=out_n,prior+=out_n) \\\n                   for (k=0; k < img_n; ++k)\n         switch (filter) {\n            CASE(STBI__F_none)         cur[k] = raw[k]; break;\n            CASE(STBI__F_sub)          cur[k] = STBI__BYTECAST(raw[k] + cur[k-out_n]); break;\n            CASE(STBI__F_up)           cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;\n            CASE(STBI__F_avg)          cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-out_n])>>1)); break;\n            CASE(STBI__F_paeth)        cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],prior[k],prior[k-out_n])); break;\n            CASE(STBI__F_avg_first)    cur[k] = STBI__BYTECAST(raw[k] + (cur[k-out_n] >> 1)); break;\n            CASE(STBI__F_paeth_first)  cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-out_n],0,0)); break;\n         }\n         #undef CASE\n      }\n   }\n\n   // we make a separate pass to expand bits to pixels; for performance,\n   // this could run two scanlines behind the above code, so it won't\n   // interfere with filtering but will still be in the cache.\n   if (depth < 8) {\n      for (j=0; j < y; ++j) {\n         stbi_uc *cur = a->out + stride*j;\n         stbi_uc *in  = a->out + stride*j + x*out_n - img_width_bytes;\n         // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit\n         // png guarantee byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop\n         stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range\n\n         // note that the final byte might overshoot and write more data than desired.\n         // we can allocate enough data that this never writes out of memory, but it\n         // could also overwrite the next scanline. can it overwrite non-empty data\n         // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.\n         // so we need to explicitly clamp the final ones\n\n         if (depth == 4) {\n            for (k=x*img_n; k >= 2; k-=2, ++in) {\n               *cur++ = scale * ((*in >> 4)       );\n               *cur++ = scale * ((*in     ) & 0x0f);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 4)       );\n         } else if (depth == 2) {\n            for (k=x*img_n; k >= 4; k-=4, ++in) {\n               *cur++ = scale * ((*in >> 6)       );\n               *cur++ = scale * ((*in >> 4) & 0x03);\n               *cur++ = scale * ((*in >> 2) & 0x03);\n               *cur++ = scale * ((*in     ) & 0x03);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 6)       );\n            if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);\n            if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);\n         } else if (depth == 1) {\n            for (k=x*img_n; k >= 8; k-=8, ++in) {\n               *cur++ = scale * ((*in >> 7)       );\n               *cur++ = scale * ((*in >> 6) & 0x01);\n               *cur++ = scale * ((*in >> 5) & 0x01);\n               *cur++ = scale * ((*in >> 4) & 0x01);\n               *cur++ = scale * ((*in >> 3) & 0x01);\n               *cur++ = scale * ((*in >> 2) & 0x01);\n               *cur++ = scale * ((*in >> 1) & 0x01);\n               *cur++ = scale * ((*in     ) & 0x01);\n            }\n            if (k > 0) *cur++ = scale * ((*in >> 7)       );\n            if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);\n            if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);\n            if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);\n            if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);\n            if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);\n            if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);\n         }\n         if (img_n != out_n) {\n            int q;\n            // insert alpha = 255\n            cur = a->out + stride*j;\n            if (img_n == 1) {\n               for (q=x-1; q >= 0; --q) {\n                  cur[q*2+1] = 255;\n                  cur[q*2+0] = cur[q];\n               }\n            } else {\n               STBI_ASSERT(img_n == 3);\n               for (q=x-1; q >= 0; --q) {\n                  cur[q*4+3] = 255;\n                  cur[q*4+2] = cur[q*3+2];\n                  cur[q*4+1] = cur[q*3+1];\n                  cur[q*4+0] = cur[q*3+0];\n               }\n            }\n         }\n      }\n   }\n\n   return 1;\n}\n\nstatic int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)\n{\n   stbi_uc *final;\n   int p;\n   if (!interlaced)\n      return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);\n\n   // de-interlacing\n   final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n);\n   for (p=0; p < 7; ++p) {\n      int xorig[] = { 0,4,0,2,0,1,0 };\n      int yorig[] = { 0,0,4,0,2,0,1 };\n      int xspc[]  = { 8,8,4,4,2,2,1 };\n      int yspc[]  = { 8,8,8,4,4,2,2 };\n      int i,j,x,y;\n      // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1\n      x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];\n      y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];\n      if (x && y) {\n         stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;\n         if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {\n            STBI_FREE(final);\n            return 0;\n         }\n         for (j=0; j < y; ++j) {\n            for (i=0; i < x; ++i) {\n               int out_y = j*yspc[p]+yorig[p];\n               int out_x = i*xspc[p]+xorig[p];\n               memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n,\n                      a->out + (j*x+i)*out_n, out_n);\n            }\n         }\n         STBI_FREE(a->out);\n         image_data += img_len;\n         image_data_len -= img_len;\n      }\n   }\n   a->out = final;\n\n   return 1;\n}\n\nstatic int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi_uc *p = z->out;\n\n   // compute color-based transparency, assuming we've\n   // already got 255 as the alpha value in the output\n   STBI_ASSERT(out_n == 2 || out_n == 4);\n\n   if (out_n == 2) {\n      for (i=0; i < pixel_count; ++i) {\n         p[1] = (p[0] == tc[0] ? 0 : 255);\n         p += 2;\n      }\n   } else {\n      for (i=0; i < pixel_count; ++i) {\n         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])\n            p[3] = 0;\n         p += 4;\n      }\n   }\n   return 1;\n}\n\nstatic int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)\n{\n   stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;\n   stbi_uc *p, *temp_out, *orig = a->out;\n\n   p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n);\n   if (p == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n\n   // between here and free(out) below, exiting would leak\n   temp_out = p;\n\n   if (pal_img_n == 3) {\n      for (i=0; i < pixel_count; ++i) {\n         int n = orig[i]*4;\n         p[0] = palette[n  ];\n         p[1] = palette[n+1];\n         p[2] = palette[n+2];\n         p += 3;\n      }\n   } else {\n      for (i=0; i < pixel_count; ++i) {\n         int n = orig[i]*4;\n         p[0] = palette[n  ];\n         p[1] = palette[n+1];\n         p[2] = palette[n+2];\n         p[3] = palette[n+3];\n         p += 4;\n      }\n   }\n   STBI_FREE(a->out);\n   a->out = temp_out;\n\n   STBI_NOTUSED(len);\n\n   return 1;\n}\n\nstatic int stbi__unpremultiply_on_load = 0;\nstatic int stbi__de_iphone_flag = 0;\n\nSTBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)\n{\n   stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;\n}\n\nSTBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)\n{\n   stbi__de_iphone_flag = flag_true_if_should_convert;\n}\n\nstatic void stbi__de_iphone(stbi__png *z)\n{\n   stbi__context *s = z->s;\n   stbi__uint32 i, pixel_count = s->img_x * s->img_y;\n   stbi_uc *p = z->out;\n\n   if (s->img_out_n == 3) {  // convert bgr to rgb\n      for (i=0; i < pixel_count; ++i) {\n         stbi_uc t = p[0];\n         p[0] = p[2];\n         p[2] = t;\n         p += 3;\n      }\n   } else {\n      STBI_ASSERT(s->img_out_n == 4);\n      if (stbi__unpremultiply_on_load) {\n         // convert bgr to rgb and unpremultiply\n         for (i=0; i < pixel_count; ++i) {\n            stbi_uc a = p[3];\n            stbi_uc t = p[0];\n            if (a) {\n               p[0] = p[2] * 255 / a;\n               p[1] = p[1] * 255 / a;\n               p[2] =  t   * 255 / a;\n            } else {\n               p[0] = p[2];\n               p[2] = t;\n            }\n            p += 4;\n         }\n      } else {\n         // convert bgr to rgb\n         for (i=0; i < pixel_count; ++i) {\n            stbi_uc t = p[0];\n            p[0] = p[2];\n            p[2] = t;\n            p += 4;\n         }\n      }\n   }\n}\n\n#define STBI__PNG_TYPE(a,b,c,d)  (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))\n\nstatic int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)\n{\n   stbi_uc palette[1024], pal_img_n=0;\n   stbi_uc has_trans=0, tc[3];\n   stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;\n   int first=1,k,interlace=0, color=0, depth=0, is_iphone=0;\n   stbi__context *s = z->s;\n\n   z->expanded = NULL;\n   z->idata = NULL;\n   z->out = NULL;\n\n   if (!stbi__check_png_header(s)) return 0;\n\n   if (scan == STBI__SCAN_type) return 1;\n\n   for (;;) {\n      stbi__pngchunk c = stbi__get_chunk_header(s);\n      switch (c.type) {\n         case STBI__PNG_TYPE('C','g','B','I'):\n            is_iphone = 1;\n            stbi__skip(s, c.length);\n            break;\n         case STBI__PNG_TYPE('I','H','D','R'): {\n            int comp,filter;\n            if (!first) return stbi__err(\"multiple IHDR\",\"Corrupt PNG\");\n            first = 0;\n            if (c.length != 13) return stbi__err(\"bad IHDR len\",\"Corrupt PNG\");\n            s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n            s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err(\"too large\",\"Very large image (corrupt?)\");\n            depth = stbi__get8(s);  if (depth != 1 && depth != 2 && depth != 4 && depth != 8)  return stbi__err(\"1/2/4/8-bit only\",\"PNG not supported: 1/2/4/8-bit only\");\n            color = stbi__get8(s);  if (color > 6)         return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err(\"bad ctype\",\"Corrupt PNG\");\n            comp  = stbi__get8(s);  if (comp) return stbi__err(\"bad comp method\",\"Corrupt PNG\");\n            filter= stbi__get8(s);  if (filter) return stbi__err(\"bad filter method\",\"Corrupt PNG\");\n            interlace = stbi__get8(s); if (interlace>1) return stbi__err(\"bad interlace method\",\"Corrupt PNG\");\n            if (!s->img_x || !s->img_y) return stbi__err(\"0-pixel image\",\"Corrupt PNG\");\n            if (!pal_img_n) {\n               s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);\n               if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err(\"too large\", \"Image too large to decode\");\n               if (scan == STBI__SCAN_header) return 1;\n            } else {\n               // if paletted, then pal_n is our final components, and\n               // img_n is # components to decompress/filter.\n               s->img_n = 1;\n               if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err(\"too large\",\"Corrupt PNG\");\n               // if SCAN_header, have to scan to see if we have a tRNS\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('P','L','T','E'):  {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (c.length > 256*3) return stbi__err(\"invalid PLTE\",\"Corrupt PNG\");\n            pal_len = c.length / 3;\n            if (pal_len * 3 != c.length) return stbi__err(\"invalid PLTE\",\"Corrupt PNG\");\n            for (i=0; i < pal_len; ++i) {\n               palette[i*4+0] = stbi__get8(s);\n               palette[i*4+1] = stbi__get8(s);\n               palette[i*4+2] = stbi__get8(s);\n               palette[i*4+3] = 255;\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('t','R','N','S'): {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (z->idata) return stbi__err(\"tRNS after IDAT\",\"Corrupt PNG\");\n            if (pal_img_n) {\n               if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }\n               if (pal_len == 0) return stbi__err(\"tRNS before PLTE\",\"Corrupt PNG\");\n               if (c.length > pal_len) return stbi__err(\"bad tRNS len\",\"Corrupt PNG\");\n               pal_img_n = 4;\n               for (i=0; i < c.length; ++i)\n                  palette[i*4+3] = stbi__get8(s);\n            } else {\n               if (!(s->img_n & 1)) return stbi__err(\"tRNS with alpha\",\"Corrupt PNG\");\n               if (c.length != (stbi__uint32) s->img_n*2) return stbi__err(\"bad tRNS len\",\"Corrupt PNG\");\n               has_trans = 1;\n               for (k=0; k < s->img_n; ++k)\n                  tc[k] = (stbi_uc) (stbi__get16be(s) & 255) * stbi__depth_scale_table[depth]; // non 8-bit images will be larger\n            }\n            break;\n         }\n\n         case STBI__PNG_TYPE('I','D','A','T'): {\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (pal_img_n && !pal_len) return stbi__err(\"no PLTE\",\"Corrupt PNG\");\n            if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }\n            if ((int)(ioff + c.length) < (int)ioff) return 0;\n            if (ioff + c.length > idata_limit) {\n               stbi_uc *p;\n               if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;\n               while (ioff + c.length > idata_limit)\n                  idata_limit *= 2;\n               p = (stbi_uc *) STBI_REALLOC(z->idata, idata_limit); if (p == NULL) return stbi__err(\"outofmem\", \"Out of memory\");\n               z->idata = p;\n            }\n            if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err(\"outofdata\",\"Corrupt PNG\");\n            ioff += c.length;\n            break;\n         }\n\n         case STBI__PNG_TYPE('I','E','N','D'): {\n            stbi__uint32 raw_len, bpl;\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if (scan != STBI__SCAN_load) return 1;\n            if (z->idata == NULL) return stbi__err(\"no IDAT\",\"Corrupt PNG\");\n            // initial guess for decoded data size to avoid unnecessary reallocs\n            bpl = (s->img_x * depth + 7) / 8; // bytes per line, per component\n            raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;\n            z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);\n            if (z->expanded == NULL) return 0; // zlib should set error\n            STBI_FREE(z->idata); z->idata = NULL;\n            if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)\n               s->img_out_n = s->img_n+1;\n            else\n               s->img_out_n = s->img_n;\n            if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, depth, color, interlace)) return 0;\n            if (has_trans)\n               if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;\n            if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)\n               stbi__de_iphone(z);\n            if (pal_img_n) {\n               // pal_img_n == 3 or 4\n               s->img_n = pal_img_n; // record the actual colors we had\n               s->img_out_n = pal_img_n;\n               if (req_comp >= 3) s->img_out_n = req_comp;\n               if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))\n                  return 0;\n            }\n            STBI_FREE(z->expanded); z->expanded = NULL;\n            return 1;\n         }\n\n         default:\n            // if critical, fail\n            if (first) return stbi__err(\"first not IHDR\", \"Corrupt PNG\");\n            if ((c.type & (1 << 29)) == 0) {\n               #ifndef STBI_NO_FAILURE_STRINGS\n               // not threadsafe\n               static char invalid_chunk[] = \"XXXX PNG chunk not known\";\n               invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);\n               invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);\n               invalid_chunk[2] = STBI__BYTECAST(c.type >>  8);\n               invalid_chunk[3] = STBI__BYTECAST(c.type >>  0);\n               #endif\n               return stbi__err(invalid_chunk, \"PNG not supported: unknown PNG chunk type\");\n            }\n            stbi__skip(s, c.length);\n            break;\n      }\n      // end of PNG chunk, read and skip CRC\n      stbi__get32be(s);\n   }\n}\n\nstatic unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp)\n{\n   unsigned char *result=NULL;\n   if (req_comp < 0 || req_comp > 4) return stbi__errpuc(\"bad req_comp\", \"Internal error\");\n   if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {\n      result = p->out;\n      p->out = NULL;\n      if (req_comp && req_comp != p->s->img_out_n) {\n         result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);\n         p->s->img_out_n = req_comp;\n         if (result == NULL) return result;\n      }\n      *x = p->s->img_x;\n      *y = p->s->img_y;\n      if (n) *n = p->s->img_out_n;\n   }\n   STBI_FREE(p->out);      p->out      = NULL;\n   STBI_FREE(p->expanded); p->expanded = NULL;\n   STBI_FREE(p->idata);    p->idata    = NULL;\n\n   return result;\n}\n\nstatic unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi__png p;\n   p.s = s;\n   return stbi__do_png(&p, x,y,comp,req_comp);\n}\n\nstatic int stbi__png_test(stbi__context *s)\n{\n   int r;\n   r = stbi__check_png_header(s);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)\n{\n   if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {\n      stbi__rewind( p->s );\n      return 0;\n   }\n   if (x) *x = p->s->img_x;\n   if (y) *y = p->s->img_y;\n   if (comp) *comp = p->s->img_n;\n   return 1;\n}\n\nstatic int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   stbi__png p;\n   p.s = s;\n   return stbi__png_info_raw(&p, x, y, comp);\n}\n#endif\n\n// Microsoft/Windows BMP image\n\n#ifndef STBI_NO_BMP\nstatic int stbi__bmp_test_raw(stbi__context *s)\n{\n   int r;\n   int sz;\n   if (stbi__get8(s) != 'B') return 0;\n   if (stbi__get8(s) != 'M') return 0;\n   stbi__get32le(s); // discard filesize\n   stbi__get16le(s); // discard reserved\n   stbi__get16le(s); // discard reserved\n   stbi__get32le(s); // discard data offset\n   sz = stbi__get32le(s);\n   r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);\n   return r;\n}\n\nstatic int stbi__bmp_test(stbi__context *s)\n{\n   int r = stbi__bmp_test_raw(s);\n   stbi__rewind(s);\n   return r;\n}\n\n\n// returns 0..31 for the highest set bit\nstatic int stbi__high_bit(unsigned int z)\n{\n   int n=0;\n   if (z == 0) return -1;\n   if (z >= 0x10000) n += 16, z >>= 16;\n   if (z >= 0x00100) n +=  8, z >>=  8;\n   if (z >= 0x00010) n +=  4, z >>=  4;\n   if (z >= 0x00004) n +=  2, z >>=  2;\n   if (z >= 0x00002) n +=  1, z >>=  1;\n   return n;\n}\n\nstatic int stbi__bitcount(unsigned int a)\n{\n   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); // max 2\n   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); // max 4\n   a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits\n   a = (a + (a >> 8)); // max 16 per 8 bits\n   a = (a + (a >> 16)); // max 32 per 8 bits\n   return a & 0xff;\n}\n\nstatic int stbi__shiftsigned(int v, int shift, int bits)\n{\n   int result;\n   int z=0;\n\n   if (shift < 0) v <<= -shift;\n   else v >>= shift;\n   result = v;\n\n   z = bits;\n   while (z < 8) {\n      result += v >> z;\n      z += bits;\n   }\n   return result;\n}\n\nstatic stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi_uc *out;\n   unsigned int mr=0,mg=0,mb=0,ma=0, all_a=255;\n   stbi_uc pal[256][4];\n   int psize=0,i,j,compress=0,width;\n   int bpp, flip_vertically, pad, target, offset, hsz;\n   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc(\"not BMP\", \"Corrupt BMP\");\n   stbi__get32le(s); // discard filesize\n   stbi__get16le(s); // discard reserved\n   stbi__get16le(s); // discard reserved\n   offset = stbi__get32le(s);\n   hsz = stbi__get32le(s);\n   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc(\"unknown BMP\", \"BMP type not supported: unknown\");\n   if (hsz == 12) {\n      s->img_x = stbi__get16le(s);\n      s->img_y = stbi__get16le(s);\n   } else {\n      s->img_x = stbi__get32le(s);\n      s->img_y = stbi__get32le(s);\n   }\n   if (stbi__get16le(s) != 1) return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n   bpp = stbi__get16le(s);\n   if (bpp == 1) return stbi__errpuc(\"monochrome\", \"BMP type not supported: 1-bit\");\n   flip_vertically = ((int) s->img_y) > 0;\n   s->img_y = abs((int) s->img_y);\n   if (hsz == 12) {\n      if (bpp < 24)\n         psize = (offset - 14 - 24) / 3;\n   } else {\n      compress = stbi__get32le(s);\n      if (compress == 1 || compress == 2) return stbi__errpuc(\"BMP RLE\", \"BMP type not supported: RLE\");\n      stbi__get32le(s); // discard sizeof\n      stbi__get32le(s); // discard hres\n      stbi__get32le(s); // discard vres\n      stbi__get32le(s); // discard colorsused\n      stbi__get32le(s); // discard max important\n      if (hsz == 40 || hsz == 56) {\n         if (hsz == 56) {\n            stbi__get32le(s);\n            stbi__get32le(s);\n            stbi__get32le(s);\n            stbi__get32le(s);\n         }\n         if (bpp == 16 || bpp == 32) {\n            mr = mg = mb = 0;\n            if (compress == 0) {\n               if (bpp == 32) {\n                  mr = 0xffu << 16;\n                  mg = 0xffu <<  8;\n                  mb = 0xffu <<  0;\n                  ma = 0xffu << 24;\n                  all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0\n               } else {\n                  mr = 31u << 10;\n                  mg = 31u <<  5;\n                  mb = 31u <<  0;\n               }\n            } else if (compress == 3) {\n               mr = stbi__get32le(s);\n               mg = stbi__get32le(s);\n               mb = stbi__get32le(s);\n               // not documented, but generated by photoshop and handled by mspaint\n               if (mr == mg && mg == mb) {\n                  // ?!?!?\n                  return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n               }\n            } else\n               return stbi__errpuc(\"bad BMP\", \"bad BMP\");\n         }\n      } else {\n         STBI_ASSERT(hsz == 108 || hsz == 124);\n         mr = stbi__get32le(s);\n         mg = stbi__get32le(s);\n         mb = stbi__get32le(s);\n         ma = stbi__get32le(s);\n         stbi__get32le(s); // discard color space\n         for (i=0; i < 12; ++i)\n            stbi__get32le(s); // discard color space parameters\n         if (hsz == 124) {\n            stbi__get32le(s); // discard rendering intent\n            stbi__get32le(s); // discard offset of profile data\n            stbi__get32le(s); // discard size of profile data\n            stbi__get32le(s); // discard reserved\n         }\n      }\n      if (bpp < 16)\n         psize = (offset - 14 - hsz) >> 2;\n   }\n   s->img_n = ma ? 4 : 3;\n   if (req_comp && req_comp >= 3) // we can directly decode 3 or 4\n      target = req_comp;\n   else\n      target = s->img_n; // if they want monochrome, we'll post-convert\n   out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y);\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   if (bpp < 16) {\n      int z=0;\n      if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc(\"invalid\", \"Corrupt BMP\"); }\n      for (i=0; i < psize; ++i) {\n         pal[i][2] = stbi__get8(s);\n         pal[i][1] = stbi__get8(s);\n         pal[i][0] = stbi__get8(s);\n         if (hsz != 12) stbi__get8(s);\n         pal[i][3] = 255;\n      }\n      stbi__skip(s, offset - 14 - hsz - psize * (hsz == 12 ? 3 : 4));\n      if (bpp == 4) width = (s->img_x + 1) >> 1;\n      else if (bpp == 8) width = s->img_x;\n      else { STBI_FREE(out); return stbi__errpuc(\"bad bpp\", \"Corrupt BMP\"); }\n      pad = (-width)&3;\n      for (j=0; j < (int) s->img_y; ++j) {\n         for (i=0; i < (int) s->img_x; i += 2) {\n            int v=stbi__get8(s),v2=0;\n            if (bpp == 4) {\n               v2 = v & 15;\n               v >>= 4;\n            }\n            out[z++] = pal[v][0];\n            out[z++] = pal[v][1];\n            out[z++] = pal[v][2];\n            if (target == 4) out[z++] = 255;\n            if (i+1 == (int) s->img_x) break;\n            v = (bpp == 8) ? stbi__get8(s) : v2;\n            out[z++] = pal[v][0];\n            out[z++] = pal[v][1];\n            out[z++] = pal[v][2];\n            if (target == 4) out[z++] = 255;\n         }\n         stbi__skip(s, pad);\n      }\n   } else {\n      int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;\n      int z = 0;\n      int easy=0;\n      stbi__skip(s, offset - 14 - hsz);\n      if (bpp == 24) width = 3 * s->img_x;\n      else if (bpp == 16) width = 2*s->img_x;\n      else /* bpp = 32 and pad = 0 */ width=0;\n      pad = (-width) & 3;\n      if (bpp == 24) {\n         easy = 1;\n      } else if (bpp == 32) {\n         if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)\n            easy = 2;\n      }\n      if (!easy) {\n         if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc(\"bad masks\", \"Corrupt BMP\"); }\n         // right shift amt to put high bit in position #7\n         rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);\n         gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);\n         bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);\n         ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);\n      }\n      for (j=0; j < (int) s->img_y; ++j) {\n         if (easy) {\n            for (i=0; i < (int) s->img_x; ++i) {\n               unsigned char a;\n               out[z+2] = stbi__get8(s);\n               out[z+1] = stbi__get8(s);\n               out[z+0] = stbi__get8(s);\n               z += 3;\n               a = (easy == 2 ? stbi__get8(s) : 255);\n               all_a |= a;\n               if (target == 4) out[z++] = a;\n            }\n         } else {\n            for (i=0; i < (int) s->img_x; ++i) {\n               stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));\n               int a;\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));\n               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));\n               a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);\n               all_a |= a;\n               if (target == 4) out[z++] = STBI__BYTECAST(a);\n            }\n         }\n         stbi__skip(s, pad);\n      }\n   }\n   \n   // if alpha channel is all 0s, replace with all 255s\n   if (target == 4 && all_a == 0)\n      for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4)\n         out[i] = 255;\n\n   if (flip_vertically) {\n      stbi_uc t;\n      for (j=0; j < (int) s->img_y>>1; ++j) {\n         stbi_uc *p1 = out +      j     *s->img_x*target;\n         stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;\n         for (i=0; i < (int) s->img_x*target; ++i) {\n            t = p1[i], p1[i] = p2[i], p2[i] = t;\n         }\n      }\n   }\n\n   if (req_comp && req_comp != target) {\n      out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n\n   *x = s->img_x;\n   *y = s->img_y;\n   if (comp) *comp = s->img_n;\n   return out;\n}\n#endif\n\n// Targa Truevision - TGA\n// by Jonathan Dummer\n#ifndef STBI_NO_TGA\nstatic int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)\n{\n    int tga_w, tga_h, tga_comp;\n    int sz;\n    stbi__get8(s);                   // discard Offset\n    sz = stbi__get8(s);              // color type\n    if( sz > 1 ) {\n        stbi__rewind(s);\n        return 0;      // only RGB or indexed allowed\n    }\n    sz = stbi__get8(s);              // image type\n    // only RGB or grey allowed, +/- RLE\n    if ((sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11)) return 0;\n    stbi__skip(s,9);\n    tga_w = stbi__get16le(s);\n    if( tga_w < 1 ) {\n        stbi__rewind(s);\n        return 0;   // test width\n    }\n    tga_h = stbi__get16le(s);\n    if( tga_h < 1 ) {\n        stbi__rewind(s);\n        return 0;   // test height\n    }\n    sz = stbi__get8(s);               // bits per pixel\n    // only RGB or RGBA or grey allowed\n    if ((sz != 8) && (sz != 16) && (sz != 24) && (sz != 32)) {\n        stbi__rewind(s);\n        return 0;\n    }\n    tga_comp = sz;\n    if (x) *x = tga_w;\n    if (y) *y = tga_h;\n    if (comp) *comp = tga_comp / 8;\n    return 1;                   // seems to have passed everything\n}\n\nstatic int stbi__tga_test(stbi__context *s)\n{\n   int res;\n   int sz;\n   stbi__get8(s);      //   discard Offset\n   sz = stbi__get8(s);   //   color type\n   if ( sz > 1 ) return 0;   //   only RGB or indexed allowed\n   sz = stbi__get8(s);   //   image type\n   if ( (sz != 1) && (sz != 2) && (sz != 3) && (sz != 9) && (sz != 10) && (sz != 11) ) return 0;   //   only RGB or grey allowed, +/- RLE\n   stbi__get16be(s);      //   discard palette start\n   stbi__get16be(s);      //   discard palette length\n   stbi__get8(s);         //   discard bits per palette color entry\n   stbi__get16be(s);      //   discard x origin\n   stbi__get16be(s);      //   discard y origin\n   if ( stbi__get16be(s) < 1 ) return 0;      //   test width\n   if ( stbi__get16be(s) < 1 ) return 0;      //   test height\n   sz = stbi__get8(s);   //   bits per pixel\n   if ( (sz != 8) && (sz != 16) && (sz != 24) && (sz != 32) )\n      res = 0;\n   else\n      res = 1;\n   stbi__rewind(s);\n   return res;\n}\n\nstatic stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   //   read in the TGA header stuff\n   int tga_offset = stbi__get8(s);\n   int tga_indexed = stbi__get8(s);\n   int tga_image_type = stbi__get8(s);\n   int tga_is_RLE = 0;\n   int tga_palette_start = stbi__get16le(s);\n   int tga_palette_len = stbi__get16le(s);\n   int tga_palette_bits = stbi__get8(s);\n   int tga_x_origin = stbi__get16le(s);\n   int tga_y_origin = stbi__get16le(s);\n   int tga_width = stbi__get16le(s);\n   int tga_height = stbi__get16le(s);\n   int tga_bits_per_pixel = stbi__get8(s);\n   int tga_comp = tga_bits_per_pixel / 8;\n   int tga_inverted = stbi__get8(s);\n   //   image data\n   unsigned char *tga_data;\n   unsigned char *tga_palette = NULL;\n   int i, j;\n   unsigned char raw_data[4];\n   int RLE_count = 0;\n   int RLE_repeating = 0;\n   int read_next_pixel = 1;\n\n   //   do a tiny bit of processing\n   if ( tga_image_type >= 8 )\n   {\n      tga_image_type -= 8;\n      tga_is_RLE = 1;\n   }\n   /* int tga_alpha_bits = tga_inverted & 15; */\n   tga_inverted = 1 - ((tga_inverted >> 5) & 1);\n\n   //   error check\n   if ( //(tga_indexed) ||\n      (tga_width < 1) || (tga_height < 1) ||\n      (tga_image_type < 1) || (tga_image_type > 3) ||\n      ((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16) &&\n      (tga_bits_per_pixel != 24) && (tga_bits_per_pixel != 32))\n      )\n   {\n      return NULL; // we don't report this as a bad TGA because we don't even know if it's TGA\n   }\n\n   //   If I'm paletted, then I'll use the number of bits from the palette\n   if ( tga_indexed )\n   {\n      tga_comp = tga_palette_bits / 8;\n   }\n\n   //   tga info\n   *x = tga_width;\n   *y = tga_height;\n   if (comp) *comp = tga_comp;\n\n   tga_data = (unsigned char*)stbi__malloc( (size_t)tga_width * tga_height * tga_comp );\n   if (!tga_data) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   // skip to the data's starting position (offset usually = 0)\n   stbi__skip(s, tga_offset );\n\n   if ( !tga_indexed && !tga_is_RLE) {\n      for (i=0; i < tga_height; ++i) {\n         int row = tga_inverted ? tga_height -i - 1 : i;\n         stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;\n         stbi__getn(s, tga_row, tga_width * tga_comp);\n      }\n   } else  {\n      //   do I need to load a palette?\n      if ( tga_indexed)\n      {\n         //   any data to skip? (offset usually = 0)\n         stbi__skip(s, tga_palette_start );\n         //   load the palette\n         tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_palette_bits / 8 );\n         if (!tga_palette) {\n            STBI_FREE(tga_data);\n            return stbi__errpuc(\"outofmem\", \"Out of memory\");\n         }\n         if (!stbi__getn(s, tga_palette, tga_palette_len * tga_palette_bits / 8 )) {\n            STBI_FREE(tga_data);\n            STBI_FREE(tga_palette);\n            return stbi__errpuc(\"bad palette\", \"Corrupt TGA\");\n         }\n      }\n      //   load the data\n      for (i=0; i < tga_width * tga_height; ++i)\n      {\n         //   if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?\n         if ( tga_is_RLE )\n         {\n            if ( RLE_count == 0 )\n            {\n               //   yep, get the next byte as a RLE command\n               int RLE_cmd = stbi__get8(s);\n               RLE_count = 1 + (RLE_cmd & 127);\n               RLE_repeating = RLE_cmd >> 7;\n               read_next_pixel = 1;\n            } else if ( !RLE_repeating )\n            {\n               read_next_pixel = 1;\n            }\n         } else\n         {\n            read_next_pixel = 1;\n         }\n         //   OK, if I need to read a pixel, do it now\n         if ( read_next_pixel )\n         {\n            //   load however much data we did have\n            if ( tga_indexed )\n            {\n               //   read in 1 byte, then perform the lookup\n               int pal_idx = stbi__get8(s);\n               if ( pal_idx >= tga_palette_len )\n               {\n                  //   invalid index\n                  pal_idx = 0;\n               }\n               pal_idx *= tga_bits_per_pixel / 8;\n               for (j = 0; j*8 < tga_bits_per_pixel; ++j)\n               {\n                  raw_data[j] = tga_palette[pal_idx+j];\n               }\n            } else\n            {\n               //   read in the data raw\n               for (j = 0; j*8 < tga_bits_per_pixel; ++j)\n               {\n                  raw_data[j] = stbi__get8(s);\n               }\n            }\n            //   clear the reading flag for the next pixel\n            read_next_pixel = 0;\n         } // end of reading a pixel\n\n         // copy data\n         for (j = 0; j < tga_comp; ++j)\n           tga_data[i*tga_comp+j] = raw_data[j];\n\n         //   in case we're in RLE mode, keep counting down\n         --RLE_count;\n      }\n      //   do I need to invert the image?\n      if ( tga_inverted )\n      {\n         for (j = 0; j*2 < tga_height; ++j)\n         {\n            int index1 = j * tga_width * tga_comp;\n            int index2 = (tga_height - 1 - j) * tga_width * tga_comp;\n            for (i = tga_width * tga_comp; i > 0; --i)\n            {\n               unsigned char temp = tga_data[index1];\n               tga_data[index1] = tga_data[index2];\n               tga_data[index2] = temp;\n               ++index1;\n               ++index2;\n            }\n         }\n      }\n      //   clear my palette, if I had one\n      if ( tga_palette != NULL )\n      {\n         STBI_FREE( tga_palette );\n      }\n   }\n\n   // swap RGB\n   if (tga_comp >= 3)\n   {\n      unsigned char* tga_pixel = tga_data;\n      for (i=0; i < tga_width * tga_height; ++i)\n      {\n         unsigned char temp = tga_pixel[0];\n         tga_pixel[0] = tga_pixel[2];\n         tga_pixel[2] = temp;\n         tga_pixel += tga_comp;\n      }\n   }\n\n   // convert to target component count\n   if (req_comp && req_comp != tga_comp)\n      tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);\n\n   //   the things I do to get rid of an error message, and yet keep\n   //   Microsoft's C compilers happy... [8^(\n   tga_palette_start = tga_palette_len = tga_palette_bits =\n         tga_x_origin = tga_y_origin = 0;\n   //   OK, done\n   return tga_data;\n}\n#endif\n\n// *************************************************************************************************\n// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB\n\n#ifndef STBI_NO_PSD\nstatic int stbi__psd_test(stbi__context *s)\n{\n   int r = (stbi__get32be(s) == 0x38425053);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   int   pixelCount;\n   int channelCount, compression;\n   int channel, i, count, len;\n   int bitdepth;\n   int w,h;\n   stbi_uc *out;\n\n   // Check identifier\n   if (stbi__get32be(s) != 0x38425053)   // \"8BPS\"\n      return stbi__errpuc(\"not PSD\", \"Corrupt PSD image\");\n\n   // Check file type version.\n   if (stbi__get16be(s) != 1)\n      return stbi__errpuc(\"wrong version\", \"Unsupported version of PSD image\");\n\n   // Skip 6 reserved bytes.\n   stbi__skip(s, 6 );\n\n   // Read the number of channels (R, G, B, A, etc).\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16)\n      return stbi__errpuc(\"wrong channel count\", \"Unsupported number of channels in PSD image\");\n\n   // Read the rows and columns of the image.\n   h = stbi__get32be(s);\n   w = stbi__get32be(s);\n\n   // Make sure the depth is 8 bits.\n   bitdepth = stbi__get16be(s);\n   if (bitdepth != 8 && bitdepth != 16)\n      return stbi__errpuc(\"unsupported bit depth\", \"PSD bit depth is not 8 or 16 bit\");\n\n   // Make sure the color mode is RGB.\n   // Valid options are:\n   //   0: Bitmap\n   //   1: Grayscale\n   //   2: Indexed color\n   //   3: RGB color\n   //   4: CMYK color\n   //   7: Multichannel\n   //   8: Duotone\n   //   9: Lab color\n   if (stbi__get16be(s) != 3)\n      return stbi__errpuc(\"wrong color format\", \"PSD is not in RGB color format\");\n\n   // Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)\n   stbi__skip(s,stbi__get32be(s) );\n\n   // Skip the image resources.  (resolution, pen tool paths, etc)\n   stbi__skip(s, stbi__get32be(s) );\n\n   // Skip the reserved data.\n   stbi__skip(s, stbi__get32be(s) );\n\n   // Find out if the data is compressed.\n   // Known values:\n   //   0: no compression\n   //   1: RLE compressed\n   compression = stbi__get16be(s);\n   if (compression > 1)\n      return stbi__errpuc(\"bad compression\", \"PSD has an unknown compression format\");\n\n   // Create the destination image.\n   out = (stbi_uc *) stbi__malloc(4 * w*h);\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   pixelCount = w*h;\n\n   // Initialize the data to zero.\n   //memset( out, 0, pixelCount * 4 );\n\n   // Finally, the image data.\n   if (compression) {\n      // RLE as used by .PSD and .TIFF\n      // Loop until you get the number of unpacked bytes you are expecting:\n      //     Read the next source byte into n.\n      //     If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.\n      //     Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.\n      //     Else if n is 128, noop.\n      // Endloop\n\n      // The RLE-compressed data is preceded by a 2-byte data count for each row in the data,\n      // which we're going to just skip.\n      stbi__skip(s, h * channelCount * 2 );\n\n      // Read the RLE data by channel.\n      for (channel = 0; channel < 4; channel++) {\n         stbi_uc *p;\n\n         p = out+channel;\n         if (channel >= channelCount) {\n            // Fill this channel with default data.\n            for (i = 0; i < pixelCount; i++, p += 4)\n               *p = (channel == 3 ? 255 : 0);\n         } else {\n            // Read the RLE data.\n            count = 0;\n            while (count < pixelCount) {\n               len = stbi__get8(s);\n               if (len == 128) {\n                  // No-op.\n               } else if (len < 128) {\n                  // Copy next len+1 bytes literally.\n                  len++;\n                  count += len;\n                  while (len) {\n                     *p = stbi__get8(s);\n                     p += 4;\n                     len--;\n                  }\n               } else if (len > 128) {\n                  stbi_uc   val;\n                  // Next -len+1 bytes in the dest are replicated from next source byte.\n                  // (Interpret len as a negative 8-bit int.)\n                  len ^= 0x0FF;\n                  len += 2;\n                  val = stbi__get8(s);\n                  count += len;\n                  while (len) {\n                     *p = val;\n                     p += 4;\n                     len--;\n                  }\n               }\n            }\n         }\n      }\n\n   } else {\n      // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)\n      // where each channel consists of an 8-bit value for each pixel in the image.\n\n      // Read the data by channel.\n      for (channel = 0; channel < 4; channel++) {\n         stbi_uc *p;\n\n         p = out + channel;\n         if (channel >= channelCount) {\n            // Fill this channel with default data.\n            stbi_uc val = channel == 3 ? 255 : 0;\n            for (i = 0; i < pixelCount; i++, p += 4)\n               *p = val;\n         } else {\n            // Read the data.\n            if (bitdepth == 16) {\n               for (i = 0; i < pixelCount; i++, p += 4)\n                  *p = (stbi_uc) (stbi__get16be(s) >> 8);\n            } else {\n               for (i = 0; i < pixelCount; i++, p += 4)\n                  *p = stbi__get8(s);\n            }\n         }\n      }\n   }\n\n   if (req_comp && req_comp != 4) {\n      out = stbi__convert_format(out, 4, req_comp, w, h);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n\n   if (comp) *comp = 4;\n   *y = h;\n   *x = w;\n\n   return out;\n}\n#endif\n\n// *************************************************************************************************\n// Softimage PIC loader\n// by Tom Seddon\n//\n// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format\n// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/\n\n#ifndef STBI_NO_PIC\nstatic int stbi__pic_is4(stbi__context *s,const char *str)\n{\n   int i;\n   for (i=0; i<4; ++i)\n      if (stbi__get8(s) != (stbi_uc)str[i])\n         return 0;\n\n   return 1;\n}\n\nstatic int stbi__pic_test_core(stbi__context *s)\n{\n   int i;\n\n   if (!stbi__pic_is4(s,\"\\x53\\x80\\xF6\\x34\"))\n      return 0;\n\n   for(i=0;i<84;++i)\n      stbi__get8(s);\n\n   if (!stbi__pic_is4(s,\"PICT\"))\n      return 0;\n\n   return 1;\n}\n\ntypedef struct\n{\n   stbi_uc size,type,channel;\n} stbi__pic_packet;\n\nstatic stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)\n{\n   int mask=0x80, i;\n\n   for (i=0; i<4; ++i, mask>>=1) {\n      if (channel & mask) {\n         if (stbi__at_eof(s)) return stbi__errpuc(\"bad file\",\"PIC file too short\");\n         dest[i]=stbi__get8(s);\n      }\n   }\n\n   return dest;\n}\n\nstatic void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)\n{\n   int mask=0x80,i;\n\n   for (i=0;i<4; ++i, mask>>=1)\n      if (channel&mask)\n         dest[i]=src[i];\n}\n\nstatic stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)\n{\n   int act_comp=0,num_packets=0,y,chained;\n   stbi__pic_packet packets[10];\n\n   // this will (should...) cater for even some bizarre stuff like having data\n    // for the same channel in multiple packets.\n   do {\n      stbi__pic_packet *packet;\n\n      if (num_packets==sizeof(packets)/sizeof(packets[0]))\n         return stbi__errpuc(\"bad format\",\"too many packets\");\n\n      packet = &packets[num_packets++];\n\n      chained = stbi__get8(s);\n      packet->size    = stbi__get8(s);\n      packet->type    = stbi__get8(s);\n      packet->channel = stbi__get8(s);\n\n      act_comp |= packet->channel;\n\n      if (stbi__at_eof(s))          return stbi__errpuc(\"bad file\",\"file too short (reading packets)\");\n      if (packet->size != 8)  return stbi__errpuc(\"bad format\",\"packet isn't 8bpp\");\n   } while (chained);\n\n   *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?\n\n   for(y=0; y<height; ++y) {\n      int packet_idx;\n\n      for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {\n         stbi__pic_packet *packet = &packets[packet_idx];\n         stbi_uc *dest = result+y*width*4;\n\n         switch (packet->type) {\n            default:\n               return stbi__errpuc(\"bad format\",\"packet has bad compression type\");\n\n            case 0: {//uncompressed\n               int x;\n\n               for(x=0;x<width;++x, dest+=4)\n                  if (!stbi__readval(s,packet->channel,dest))\n                     return 0;\n               break;\n            }\n\n            case 1://Pure RLE\n               {\n                  int left=width, i;\n\n                  while (left>0) {\n                     stbi_uc count,value[4];\n\n                     count=stbi__get8(s);\n                     if (stbi__at_eof(s))   return stbi__errpuc(\"bad file\",\"file too short (pure read count)\");\n\n                     if (count > left)\n                        count = (stbi_uc) left;\n\n                     if (!stbi__readval(s,packet->channel,value))  return 0;\n\n                     for(i=0; i<count; ++i,dest+=4)\n                        stbi__copyval(packet->channel,dest,value);\n                     left -= count;\n                  }\n               }\n               break;\n\n            case 2: {//Mixed RLE\n               int left=width;\n               while (left>0) {\n                  int count = stbi__get8(s), i;\n                  if (stbi__at_eof(s))  return stbi__errpuc(\"bad file\",\"file too short (mixed read count)\");\n\n                  if (count >= 128) { // Repeated\n                     stbi_uc value[4];\n\n                     if (count==128)\n                        count = stbi__get16be(s);\n                     else\n                        count -= 127;\n                     if (count > left)\n                        return stbi__errpuc(\"bad file\",\"scanline overrun\");\n\n                     if (!stbi__readval(s,packet->channel,value))\n                        return 0;\n\n                     for(i=0;i<count;++i, dest += 4)\n                        stbi__copyval(packet->channel,dest,value);\n                  } else { // Raw\n                     ++count;\n                     if (count>left) return stbi__errpuc(\"bad file\",\"scanline overrun\");\n\n                     for(i=0;i<count;++i, dest+=4)\n                        if (!stbi__readval(s,packet->channel,dest))\n                           return 0;\n                  }\n                  left-=count;\n               }\n               break;\n            }\n         }\n      }\n   }\n\n   return result;\n}\n\nstatic stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp)\n{\n   stbi_uc *result;\n   int i, x,y;\n\n   for (i=0; i<92; ++i)\n      stbi__get8(s);\n\n   x = stbi__get16be(s);\n   y = stbi__get16be(s);\n   if (stbi__at_eof(s))  return stbi__errpuc(\"bad file\",\"file too short (pic header)\");\n   if ((1 << 28) / x < y) return stbi__errpuc(\"too large\", \"Image too large to decode\");\n\n   stbi__get32be(s); //skip `ratio'\n   stbi__get16be(s); //skip `fields'\n   stbi__get16be(s); //skip `pad'\n\n   // intermediate buffer is RGBA\n   result = (stbi_uc *) stbi__malloc(x*y*4);\n   memset(result, 0xff, x*y*4);\n\n   if (!stbi__pic_load_core(s,x,y,comp, result)) {\n      STBI_FREE(result);\n      result=0;\n   }\n   *px = x;\n   *py = y;\n   if (req_comp == 0) req_comp = *comp;\n   result=stbi__convert_format(result,4,req_comp,x,y);\n\n   return result;\n}\n\nstatic int stbi__pic_test(stbi__context *s)\n{\n   int r = stbi__pic_test_core(s);\n   stbi__rewind(s);\n   return r;\n}\n#endif\n\n// *************************************************************************************************\n// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb\n\n#ifndef STBI_NO_GIF\ntypedef struct\n{\n   stbi__int16 prefix;\n   stbi_uc first;\n   stbi_uc suffix;\n} stbi__gif_lzw;\n\ntypedef struct\n{\n   int w,h;\n   stbi_uc *out, *old_out;             // output buffer (always 4 components)\n   int flags, bgindex, ratio, transparent, eflags, delay;\n   stbi_uc  pal[256][4];\n   stbi_uc lpal[256][4];\n   stbi__gif_lzw codes[4096];\n   stbi_uc *color_table;\n   int parse, step;\n   int lflags;\n   int start_x, start_y;\n   int max_x, max_y;\n   int cur_x, cur_y;\n   int line_size;\n} stbi__gif;\n\nstatic int stbi__gif_test_raw(stbi__context *s)\n{\n   int sz;\n   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;\n   sz = stbi__get8(s);\n   if (sz != '9' && sz != '7') return 0;\n   if (stbi__get8(s) != 'a') return 0;\n   return 1;\n}\n\nstatic int stbi__gif_test(stbi__context *s)\n{\n   int r = stbi__gif_test_raw(s);\n   stbi__rewind(s);\n   return r;\n}\n\nstatic void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)\n{\n   int i;\n   for (i=0; i < num_entries; ++i) {\n      pal[i][2] = stbi__get8(s);\n      pal[i][1] = stbi__get8(s);\n      pal[i][0] = stbi__get8(s);\n      pal[i][3] = transp == i ? 0 : 255;\n   }\n}\n\nstatic int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)\n{\n   stbi_uc version;\n   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')\n      return stbi__err(\"not GIF\", \"Corrupt GIF\");\n\n   version = stbi__get8(s);\n   if (version != '7' && version != '9')    return stbi__err(\"not GIF\", \"Corrupt GIF\");\n   if (stbi__get8(s) != 'a')                return stbi__err(\"not GIF\", \"Corrupt GIF\");\n\n   stbi__g_failure_reason = \"\";\n   g->w = stbi__get16le(s);\n   g->h = stbi__get16le(s);\n   g->flags = stbi__get8(s);\n   g->bgindex = stbi__get8(s);\n   g->ratio = stbi__get8(s);\n   g->transparent = -1;\n\n   if (comp != 0) *comp = 4;  // can't actually tell whether it's 3 or 4 until we parse the comments\n\n   if (is_info) return 1;\n\n   if (g->flags & 0x80)\n      stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);\n\n   return 1;\n}\n\nstatic int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)\n{\n   stbi__gif g;\n   if (!stbi__gif_header(s, &g, comp, 1)) {\n      stbi__rewind( s );\n      return 0;\n   }\n   if (x) *x = g.w;\n   if (y) *y = g.h;\n   return 1;\n}\n\nstatic void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)\n{\n   stbi_uc *p, *c;\n\n   // recurse to decode the prefixes, since the linked-list is backwards,\n   // and working backwards through an interleaved image would be nasty\n   if (g->codes[code].prefix >= 0)\n      stbi__out_gif_code(g, g->codes[code].prefix);\n\n   if (g->cur_y >= g->max_y) return;\n\n   p = &g->out[g->cur_x + g->cur_y];\n   c = &g->color_table[g->codes[code].suffix * 4];\n\n   if (c[3] >= 128) {\n      p[0] = c[2];\n      p[1] = c[1];\n      p[2] = c[0];\n      p[3] = c[3];\n   }\n   g->cur_x += 4;\n\n   if (g->cur_x >= g->max_x) {\n      g->cur_x = g->start_x;\n      g->cur_y += g->step;\n\n      while (g->cur_y >= g->max_y && g->parse > 0) {\n         g->step = (1 << g->parse) * g->line_size;\n         g->cur_y = g->start_y + (g->step >> 1);\n         --g->parse;\n      }\n   }\n}\n\nstatic stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)\n{\n   stbi_uc lzw_cs;\n   stbi__int32 len, init_code;\n   stbi__uint32 first;\n   stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;\n   stbi__gif_lzw *p;\n\n   lzw_cs = stbi__get8(s);\n   if (lzw_cs > 12) return NULL;\n   clear = 1 << lzw_cs;\n   first = 1;\n   codesize = lzw_cs + 1;\n   codemask = (1 << codesize) - 1;\n   bits = 0;\n   valid_bits = 0;\n   for (init_code = 0; init_code < clear; init_code++) {\n      g->codes[init_code].prefix = -1;\n      g->codes[init_code].first = (stbi_uc) init_code;\n      g->codes[init_code].suffix = (stbi_uc) init_code;\n   }\n\n   // support no starting clear code\n   avail = clear+2;\n   oldcode = -1;\n\n   len = 0;\n   for(;;) {\n      if (valid_bits < codesize) {\n         if (len == 0) {\n            len = stbi__get8(s); // start new block\n            if (len == 0)\n               return g->out;\n         }\n         --len;\n         bits |= (stbi__int32) stbi__get8(s) << valid_bits;\n         valid_bits += 8;\n      } else {\n         stbi__int32 code = bits & codemask;\n         bits >>= codesize;\n         valid_bits -= codesize;\n         // @OPTIMIZE: is there some way we can accelerate the non-clear path?\n         if (code == clear) {  // clear code\n            codesize = lzw_cs + 1;\n            codemask = (1 << codesize) - 1;\n            avail = clear + 2;\n            oldcode = -1;\n            first = 0;\n         } else if (code == clear + 1) { // end of stream code\n            stbi__skip(s, len);\n            while ((len = stbi__get8(s)) > 0)\n               stbi__skip(s,len);\n            return g->out;\n         } else if (code <= avail) {\n            if (first) return stbi__errpuc(\"no clear code\", \"Corrupt GIF\");\n\n            if (oldcode >= 0) {\n               p = &g->codes[avail++];\n               if (avail > 4096)        return stbi__errpuc(\"too many codes\", \"Corrupt GIF\");\n               p->prefix = (stbi__int16) oldcode;\n               p->first = g->codes[oldcode].first;\n               p->suffix = (code == avail) ? p->first : g->codes[code].first;\n            } else if (code == avail)\n               return stbi__errpuc(\"illegal code in raster\", \"Corrupt GIF\");\n\n            stbi__out_gif_code(g, (stbi__uint16) code);\n\n            if ((avail & codemask) == 0 && avail <= 0x0FFF) {\n               codesize++;\n               codemask = (1 << codesize) - 1;\n            }\n\n            oldcode = code;\n         } else {\n            return stbi__errpuc(\"illegal code in raster\", \"Corrupt GIF\");\n         }\n      }\n   }\n}\n\nstatic void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1)\n{\n   int x, y;\n   stbi_uc *c = g->pal[g->bgindex];\n   for (y = y0; y < y1; y += 4 * g->w) {\n      for (x = x0; x < x1; x += 4) {\n         stbi_uc *p  = &g->out[y + x];\n         p[0] = c[2];\n         p[1] = c[1];\n         p[2] = c[0];\n         p[3] = 0;\n      }\n   }\n}\n\n// this function is designed to support animated gifs, although stb_image doesn't support it\nstatic stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp)\n{\n   int i;\n   stbi_uc *prev_out = 0;\n\n   if (g->out == 0 && !stbi__gif_header(s, g, comp,0))\n      return 0; // stbi__g_failure_reason set by stbi__gif_header\n\n   prev_out = g->out;\n   g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h);\n   if (g->out == 0) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n\n   switch ((g->eflags & 0x1C) >> 2) {\n      case 0: // unspecified (also always used on 1st frame)\n         stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h);\n         break;\n      case 1: // do not dispose\n         if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);\n         g->old_out = prev_out;\n         break;\n      case 2: // dispose to background\n         if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);\n         stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y);\n         break;\n      case 3: // dispose to previous\n         if (g->old_out) {\n            for (i = g->start_y; i < g->max_y; i += 4 * g->w)\n               memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x);\n         }\n         break;\n   }\n\n   for (;;) {\n      switch (stbi__get8(s)) {\n         case 0x2C: /* Image Descriptor */\n         {\n            int prev_trans = -1;\n            stbi__int32 x, y, w, h;\n            stbi_uc *o;\n\n            x = stbi__get16le(s);\n            y = stbi__get16le(s);\n            w = stbi__get16le(s);\n            h = stbi__get16le(s);\n            if (((x + w) > (g->w)) || ((y + h) > (g->h)))\n               return stbi__errpuc(\"bad Image Descriptor\", \"Corrupt GIF\");\n\n            g->line_size = g->w * 4;\n            g->start_x = x * 4;\n            g->start_y = y * g->line_size;\n            g->max_x   = g->start_x + w * 4;\n            g->max_y   = g->start_y + h * g->line_size;\n            g->cur_x   = g->start_x;\n            g->cur_y   = g->start_y;\n\n            g->lflags = stbi__get8(s);\n\n            if (g->lflags & 0x40) {\n               g->step = 8 * g->line_size; // first interlaced spacing\n               g->parse = 3;\n            } else {\n               g->step = g->line_size;\n               g->parse = 0;\n            }\n\n            if (g->lflags & 0x80) {\n               stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);\n               g->color_table = (stbi_uc *) g->lpal;\n            } else if (g->flags & 0x80) {\n               if (g->transparent >= 0 && (g->eflags & 0x01)) {\n                  prev_trans = g->pal[g->transparent][3];\n                  g->pal[g->transparent][3] = 0;\n               }\n               g->color_table = (stbi_uc *) g->pal;\n            } else\n               return stbi__errpuc(\"missing color table\", \"Corrupt GIF\");\n\n            o = stbi__process_gif_raster(s, g);\n            if (o == NULL) return NULL;\n\n            if (prev_trans != -1)\n               g->pal[g->transparent][3] = (stbi_uc) prev_trans;\n\n            return o;\n         }\n\n         case 0x21: // Comment Extension.\n         {\n            int len;\n            if (stbi__get8(s) == 0xF9) { // Graphic Control Extension.\n               len = stbi__get8(s);\n               if (len == 4) {\n                  g->eflags = stbi__get8(s);\n                  g->delay = stbi__get16le(s);\n                  g->transparent = stbi__get8(s);\n               } else {\n                  stbi__skip(s, len);\n                  break;\n               }\n            }\n            while ((len = stbi__get8(s)) != 0)\n               stbi__skip(s, len);\n            break;\n         }\n\n         case 0x3B: // gif stream termination code\n            return (stbi_uc *) s; // using '1' causes warning on some compilers\n\n         default:\n            return stbi__errpuc(\"unknown code\", \"Corrupt GIF\");\n      }\n   }\n\n   STBI_NOTUSED(req_comp);\n}\n\nstatic stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi_uc *u = 0;\n   stbi__gif g;\n   memset(&g, 0, sizeof(g));\n\n   u = stbi__gif_load_next(s, &g, comp, req_comp);\n   if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker\n   if (u) {\n      *x = g.w;\n      *y = g.h;\n      if (req_comp && req_comp != 4)\n         u = stbi__convert_format(u, 4, req_comp, g.w, g.h);\n   }\n   else if (g.out)\n      STBI_FREE(g.out);\n\n   return u;\n}\n\nstatic int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   return stbi__gif_info_raw(s,x,y,comp);\n}\n#endif\n\n// *************************************************************************************************\n// Radiance RGBE HDR loader\n// originally by Nicolas Schulz\n#ifndef STBI_NO_HDR\nstatic int stbi__hdr_test_core(stbi__context *s)\n{\n   const char *signature = \"#?RADIANCE\\n\";\n   int i;\n   for (i=0; signature[i]; ++i)\n      if (stbi__get8(s) != signature[i])\n         return 0;\n   return 1;\n}\n\nstatic int stbi__hdr_test(stbi__context* s)\n{\n   int r = stbi__hdr_test_core(s);\n   stbi__rewind(s);\n   return r;\n}\n\n#define STBI__HDR_BUFLEN  1024\nstatic char *stbi__hdr_gettoken(stbi__context *z, char *buffer)\n{\n   int len=0;\n   char c = '\\0';\n\n   c = (char) stbi__get8(z);\n\n   while (!stbi__at_eof(z) && c != '\\n') {\n      buffer[len++] = c;\n      if (len == STBI__HDR_BUFLEN-1) {\n         // flush to end of line\n         while (!stbi__at_eof(z) && stbi__get8(z) != '\\n')\n            ;\n         break;\n      }\n      c = (char) stbi__get8(z);\n   }\n\n   buffer[len] = 0;\n   return buffer;\n}\n\nstatic void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)\n{\n   if ( input[3] != 0 ) {\n      float f1;\n      // Exponent\n      f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));\n      if (req_comp <= 2)\n         output[0] = (input[0] + input[1] + input[2]) * f1 / 3;\n      else {\n         output[0] = input[0] * f1;\n         output[1] = input[1] * f1;\n         output[2] = input[2] * f1;\n      }\n      if (req_comp == 2) output[1] = 1;\n      if (req_comp == 4) output[3] = 1;\n   } else {\n      switch (req_comp) {\n         case 4: output[3] = 1; /* fallthrough */\n         case 3: output[0] = output[1] = output[2] = 0;\n                 break;\n         case 2: output[1] = 1; /* fallthrough */\n         case 1: output[0] = 0;\n                 break;\n      }\n   }\n}\n\nstatic float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   char buffer[STBI__HDR_BUFLEN];\n   char *token;\n   int valid = 0;\n   int width, height;\n   stbi_uc *scanline;\n   float *hdr_data;\n   int len;\n   unsigned char count, value;\n   int i, j, k, c1,c2, z;\n\n\n   // Check identifier\n   if (strcmp(stbi__hdr_gettoken(s,buffer), \"#?RADIANCE\") != 0)\n      return stbi__errpf(\"not HDR\", \"Corrupt HDR image\");\n\n   // Parse header\n   for(;;) {\n      token = stbi__hdr_gettoken(s,buffer);\n      if (token[0] == 0) break;\n      if (strcmp(token, \"FORMAT=32-bit_rle_rgbe\") == 0) valid = 1;\n   }\n\n   if (!valid)    return stbi__errpf(\"unsupported format\", \"Unsupported HDR format\");\n\n   // Parse width and height\n   // can't use sscanf() if we're not using stdio!\n   token = stbi__hdr_gettoken(s,buffer);\n   if (strncmp(token, \"-Y \", 3))  return stbi__errpf(\"unsupported data layout\", \"Unsupported HDR format\");\n   token += 3;\n   height = (int) strtol(token, &token, 10);\n   while (*token == ' ') ++token;\n   if (strncmp(token, \"+X \", 3))  return stbi__errpf(\"unsupported data layout\", \"Unsupported HDR format\");\n   token += 3;\n   width = (int) strtol(token, NULL, 10);\n\n   *x = width;\n   *y = height;\n\n   if (comp) *comp = 3;\n   if (req_comp == 0) req_comp = 3;\n\n   // Read data\n   hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float));\n\n   // Load image data\n   // image data is stored as some number of sca\n   if ( width < 8 || width >= 32768) {\n      // Read flat data\n      for (j=0; j < height; ++j) {\n         for (i=0; i < width; ++i) {\n            stbi_uc rgbe[4];\n           main_decode_loop:\n            stbi__getn(s, rgbe, 4);\n            stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);\n         }\n      }\n   } else {\n      // Read RLE-encoded data\n      scanline = NULL;\n\n      for (j = 0; j < height; ++j) {\n         c1 = stbi__get8(s);\n         c2 = stbi__get8(s);\n         len = stbi__get8(s);\n         if (c1 != 2 || c2 != 2 || (len & 0x80)) {\n            // not run-length encoded, so we have to actually use THIS data as a decoded\n            // pixel (note this can't be a valid pixel--one of RGB must be >= 128)\n            stbi_uc rgbe[4];\n            rgbe[0] = (stbi_uc) c1;\n            rgbe[1] = (stbi_uc) c2;\n            rgbe[2] = (stbi_uc) len;\n            rgbe[3] = (stbi_uc) stbi__get8(s);\n            stbi__hdr_convert(hdr_data, rgbe, req_comp);\n            i = 1;\n            j = 0;\n            STBI_FREE(scanline);\n            goto main_decode_loop; // yes, this makes no sense\n         }\n         len <<= 8;\n         len |= stbi__get8(s);\n         if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf(\"invalid decoded scanline length\", \"corrupt HDR\"); }\n         if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4);\n\n         for (k = 0; k < 4; ++k) {\n            i = 0;\n            while (i < width) {\n               count = stbi__get8(s);\n               if (count > 128) {\n                  // Run\n                  value = stbi__get8(s);\n                  count -= 128;\n                  for (z = 0; z < count; ++z)\n                     scanline[i++ * 4 + k] = value;\n               } else {\n                  // Dump\n                  for (z = 0; z < count; ++z)\n                     scanline[i++ * 4 + k] = stbi__get8(s);\n               }\n            }\n         }\n         for (i=0; i < width; ++i)\n            stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);\n      }\n      STBI_FREE(scanline);\n   }\n\n   return hdr_data;\n}\n\nstatic int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   char buffer[STBI__HDR_BUFLEN];\n   char *token;\n   int valid = 0;\n\n   if (strcmp(stbi__hdr_gettoken(s,buffer), \"#?RADIANCE\") != 0) {\n       stbi__rewind( s );\n       return 0;\n   }\n\n   for(;;) {\n      token = stbi__hdr_gettoken(s,buffer);\n      if (token[0] == 0) break;\n      if (strcmp(token, \"FORMAT=32-bit_rle_rgbe\") == 0) valid = 1;\n   }\n\n   if (!valid) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token = stbi__hdr_gettoken(s,buffer);\n   if (strncmp(token, \"-Y \", 3)) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token += 3;\n   *y = (int) strtol(token, &token, 10);\n   while (*token == ' ') ++token;\n   if (strncmp(token, \"+X \", 3)) {\n       stbi__rewind( s );\n       return 0;\n   }\n   token += 3;\n   *x = (int) strtol(token, NULL, 10);\n   *comp = 3;\n   return 1;\n}\n#endif // STBI_NO_HDR\n\n#ifndef STBI_NO_BMP\nstatic int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int hsz;\n   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') {\n       stbi__rewind( s );\n       return 0;\n   }\n   stbi__skip(s,12);\n   hsz = stbi__get32le(s);\n   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (hsz == 12) {\n      *x = stbi__get16le(s);\n      *y = stbi__get16le(s);\n   } else {\n      *x = stbi__get32le(s);\n      *y = stbi__get32le(s);\n   }\n   if (stbi__get16le(s) != 1) {\n       stbi__rewind( s );\n       return 0;\n   }\n   *comp = stbi__get16le(s) / 8;\n   return 1;\n}\n#endif\n\n#ifndef STBI_NO_PSD\nstatic int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int channelCount;\n   if (stbi__get32be(s) != 0x38425053) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 1) {\n       stbi__rewind( s );\n       return 0;\n   }\n   stbi__skip(s, 6);\n   channelCount = stbi__get16be(s);\n   if (channelCount < 0 || channelCount > 16) {\n       stbi__rewind( s );\n       return 0;\n   }\n   *y = stbi__get32be(s);\n   *x = stbi__get32be(s);\n   if (stbi__get16be(s) != 8) {\n       stbi__rewind( s );\n       return 0;\n   }\n   if (stbi__get16be(s) != 3) {\n       stbi__rewind( s );\n       return 0;\n   }\n   *comp = 4;\n   return 1;\n}\n#endif\n\n#ifndef STBI_NO_PIC\nstatic int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int act_comp=0,num_packets=0,chained;\n   stbi__pic_packet packets[10];\n\n   if (!stbi__pic_is4(s,\"\\x53\\x80\\xF6\\x34\")) {\n      stbi__rewind(s);\n      return 0;\n   }\n\n   stbi__skip(s, 88);\n\n   *x = stbi__get16be(s);\n   *y = stbi__get16be(s);\n   if (stbi__at_eof(s)) {\n      stbi__rewind( s);\n      return 0;\n   }\n   if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {\n      stbi__rewind( s );\n      return 0;\n   }\n\n   stbi__skip(s, 8);\n\n   do {\n      stbi__pic_packet *packet;\n\n      if (num_packets==sizeof(packets)/sizeof(packets[0]))\n         return 0;\n\n      packet = &packets[num_packets++];\n      chained = stbi__get8(s);\n      packet->size    = stbi__get8(s);\n      packet->type    = stbi__get8(s);\n      packet->channel = stbi__get8(s);\n      act_comp |= packet->channel;\n\n      if (stbi__at_eof(s)) {\n          stbi__rewind( s );\n          return 0;\n      }\n      if (packet->size != 8) {\n          stbi__rewind( s );\n          return 0;\n      }\n   } while (chained);\n\n   *comp = (act_comp & 0x10 ? 4 : 3);\n\n   return 1;\n}\n#endif\n\n// *************************************************************************************************\n// Portable Gray Map and Portable Pixel Map loader\n// by Ken Miller\n//\n// PGM: http://netpbm.sourceforge.net/doc/pgm.html\n// PPM: http://netpbm.sourceforge.net/doc/ppm.html\n//\n// Known limitations:\n//    Does not support comments in the header section\n//    Does not support ASCII image data (formats P2 and P3)\n//    Does not support 16-bit-per-channel\n\n#ifndef STBI_NO_PNM\n\nstatic int      stbi__pnm_test(stbi__context *s)\n{\n   char p, t;\n   p = (char) stbi__get8(s);\n   t = (char) stbi__get8(s);\n   if (p != 'P' || (t != '5' && t != '6')) {\n       stbi__rewind( s );\n       return 0;\n   }\n   return 1;\n}\n\nstatic stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)\n{\n   stbi_uc *out;\n   if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))\n      return 0;\n   *x = s->img_x;\n   *y = s->img_y;\n   *comp = s->img_n;\n\n   out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y);\n   if (!out) return stbi__errpuc(\"outofmem\", \"Out of memory\");\n   stbi__getn(s, out, s->img_n * s->img_x * s->img_y);\n\n   if (req_comp && req_comp != s->img_n) {\n      out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);\n      if (out == NULL) return out; // stbi__convert_format frees input on failure\n   }\n   return out;\n}\n\nstatic int      stbi__pnm_isspace(char c)\n{\n   return c == ' ' || c == '\\t' || c == '\\n' || c == '\\v' || c == '\\f' || c == '\\r';\n}\n\nstatic void     stbi__pnm_skip_whitespace(stbi__context *s, char *c)\n{\n   while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))\n      *c = (char) stbi__get8(s);\n}\n\nstatic int      stbi__pnm_isdigit(char c)\n{\n   return c >= '0' && c <= '9';\n}\n\nstatic int      stbi__pnm_getinteger(stbi__context *s, char *c)\n{\n   int value = 0;\n\n   while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {\n      value = value*10 + (*c - '0');\n      *c = (char) stbi__get8(s);\n   }\n\n   return value;\n}\n\nstatic int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)\n{\n   int maxv;\n   char c, p, t;\n\n   stbi__rewind( s );\n\n   // Get identifier\n   p = (char) stbi__get8(s);\n   t = (char) stbi__get8(s);\n   if (p != 'P' || (t != '5' && t != '6')) {\n       stbi__rewind( s );\n       return 0;\n   }\n\n   *comp = (t == '6') ? 3 : 1;  // '5' is 1-component .pgm; '6' is 3-component .ppm\n\n   c = (char) stbi__get8(s);\n   stbi__pnm_skip_whitespace(s, &c);\n\n   *x = stbi__pnm_getinteger(s, &c); // read width\n   stbi__pnm_skip_whitespace(s, &c);\n\n   *y = stbi__pnm_getinteger(s, &c); // read height\n   stbi__pnm_skip_whitespace(s, &c);\n\n   maxv = stbi__pnm_getinteger(s, &c);  // read max value\n\n   if (maxv > 255)\n      return stbi__err(\"max value > 255\", \"PPM image not 8-bit\");\n   else\n      return 1;\n}\n#endif\n\nstatic int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)\n{\n   #ifndef STBI_NO_JPEG\n   if (stbi__jpeg_info(s, x, y, comp)) return 1;\n   #endif\n\n   #ifndef STBI_NO_PNG\n   if (stbi__png_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_GIF\n   if (stbi__gif_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_BMP\n   if (stbi__bmp_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PSD\n   if (stbi__psd_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PIC\n   if (stbi__pic_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_PNM\n   if (stbi__pnm_info(s, x, y, comp))  return 1;\n   #endif\n\n   #ifndef STBI_NO_HDR\n   if (stbi__hdr_info(s, x, y, comp))  return 1;\n   #endif\n\n   // test tga last because it's a crappy test!\n   #ifndef STBI_NO_TGA\n   if (stbi__tga_info(s, x, y, comp))\n       return 1;\n   #endif\n   return stbi__err(\"unknown image type\", \"Image not of any known type, or corrupt\");\n}\n\n#ifndef STBI_NO_STDIO\nSTBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)\n{\n    FILE *f = stbi__fopen(filename, \"rb\");\n    int result;\n    if (!f) return stbi__err(\"can't fopen\", \"Unable to open file\");\n    result = stbi_info_from_file(f, x, y, comp);\n    fclose(f);\n    return result;\n}\n\nSTBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)\n{\n   int r;\n   stbi__context s;\n   long pos = ftell(f);\n   stbi__start_file(&s, f);\n   r = stbi__info_main(&s,x,y,comp);\n   fseek(f,pos,SEEK_SET);\n   return r;\n}\n#endif // !STBI_NO_STDIO\n\nSTBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)\n{\n   stbi__context s;\n   stbi__start_mem(&s,buffer,len);\n   return stbi__info_main(&s,x,y,comp);\n}\n\nSTBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)\n{\n   stbi__context s;\n   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);\n   return stbi__info_main(&s,x,y,comp);\n}\n\n#endif // STB_IMAGE_IMPLEMENTATION\n\n/*\n   revision history:\n      2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA\n      2.07  (2015-09-13) fix compiler warnings\n                         partial animated GIF support\n                         limited 16-bit PSD support\n                         #ifdef unused functions\n                         bug with < 92 byte PIC,PNM,HDR,TGA\n      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value\n      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning\n      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit\n      2.03  (2015-04-12) extra corruption checking (mmozeiko)\n                         stbi_set_flip_vertically_on_load (nguillemot)\n                         fix NEON support; fix mingw support\n      2.02  (2015-01-19) fix incorrect assert, fix warning\n      2.01  (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2\n      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG\n      2.00  (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)\n                         progressive JPEG (stb)\n                         PGM/PPM support (Ken Miller)\n                         STBI_MALLOC,STBI_REALLOC,STBI_FREE\n                         GIF bugfix -- seemingly never worked\n                         STBI_NO_*, STBI_ONLY_*\n      1.48  (2014-12-14) fix incorrectly-named assert()\n      1.47  (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)\n                         optimize PNG (ryg)\n                         fix bug in interlaced PNG with user-specified channel count (stb)\n      1.46  (2014-08-26)\n              fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG\n      1.45  (2014-08-16)\n              fix MSVC-ARM internal compiler error by wrapping malloc\n      1.44  (2014-08-07)\n              various warning fixes from Ronny Chevalier\n      1.43  (2014-07-15)\n              fix MSVC-only compiler problem in code changed in 1.42\n      1.42  (2014-07-09)\n              don't define _CRT_SECURE_NO_WARNINGS (affects user code)\n              fixes to stbi__cleanup_jpeg path\n              added STBI_ASSERT to avoid requiring assert.h\n      1.41  (2014-06-25)\n              fix search&replace from 1.36 that messed up comments/error messages\n      1.40  (2014-06-22)\n              fix gcc struct-initialization warning\n      1.39  (2014-06-15)\n              fix to TGA optimization when req_comp != number of components in TGA;\n              fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)\n              add support for BMP version 5 (more ignored fields)\n      1.38  (2014-06-06)\n              suppress MSVC warnings on integer casts truncating values\n              fix accidental rename of 'skip' field of I/O\n      1.37  (2014-06-04)\n              remove duplicate typedef\n      1.36  (2014-06-03)\n              convert to header file single-file library\n              if de-iphone isn't set, load iphone images color-swapped instead of returning NULL\n      1.35  (2014-05-27)\n              various warnings\n              fix broken STBI_SIMD path\n              fix bug where stbi_load_from_file no longer left file pointer in correct place\n              fix broken non-easy path for 32-bit BMP (possibly never used)\n              TGA optimization by Arseny Kapoulkine\n      1.34  (unknown)\n              use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case\n      1.33  (2011-07-14)\n              make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements\n      1.32  (2011-07-13)\n              support for \"info\" function for all supported filetypes (SpartanJ)\n      1.31  (2011-06-20)\n              a few more leak fixes, bug in PNG handling (SpartanJ)\n      1.30  (2011-06-11)\n              added ability to load files via callbacks to accommodate custom input streams (Ben Wenger)\n              removed deprecated format-specific test/load functions\n              removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway\n              error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)\n              fix inefficiency in decoding 32-bit BMP (David Woo)\n      1.29  (2010-08-16)\n              various warning fixes from Aurelien Pocheville\n      1.28  (2010-08-01)\n              fix bug in GIF palette transparency (SpartanJ)\n      1.27  (2010-08-01)\n              cast-to-stbi_uc to fix warnings\n      1.26  (2010-07-24)\n              fix bug in file buffering for PNG reported by SpartanJ\n      1.25  (2010-07-17)\n              refix trans_data warning (Won Chun)\n      1.24  (2010-07-12)\n              perf improvements reading from files on platforms with lock-heavy fgetc()\n              minor perf improvements for jpeg\n              deprecated type-specific functions so we'll get feedback if they're needed\n              attempt to fix trans_data warning (Won Chun)\n      1.23    fixed bug in iPhone support\n      1.22  (2010-07-10)\n              removed image *writing* support\n              stbi_info support from Jetro Lauha\n              GIF support from Jean-Marc Lienher\n              iPhone PNG-extensions from James Brown\n              warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)\n      1.21    fix use of 'stbi_uc' in header (reported by jon blow)\n      1.20    added support for Softimage PIC, by Tom Seddon\n      1.19    bug in interlaced PNG corruption check (found by ryg)\n      1.18  (2008-08-02)\n              fix a threading bug (local mutable static)\n      1.17    support interlaced PNG\n      1.16    major bugfix - stbi__convert_format converted one too many pixels\n      1.15    initialize some fields for thread safety\n      1.14    fix threadsafe conversion bug\n              header-file-only version (#define STBI_HEADER_FILE_ONLY before including)\n      1.13    threadsafe\n      1.12    const qualifiers in the API\n      1.11    Support installable IDCT, colorspace conversion routines\n      1.10    Fixes for 64-bit (don't use \"unsigned long\")\n              optimized upsampling by Fabian \"ryg\" Giesen\n      1.09    Fix format-conversion for PSD code (bad global variables!)\n      1.08    Thatcher Ulrich's PSD code integrated by Nicolas Schulz\n      1.07    attempt to fix C++ warning/errors again\n      1.06    attempt to fix C++ warning/errors again\n      1.05    fix TGA loading to return correct *comp and use good luminance calc\n      1.04    default float alpha is 1, not 255; use 'void *' for stbi_image_free\n      1.03    bugfixes to STBI_NO_STDIO, STBI_NO_HDR\n      1.02    support for (subset of) HDR files, float interface for preferred access to them\n      1.01    fix bug: possible bug in handling right-side up bmps... not sure\n              fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all\n      1.00    interface to zlib that skips zlib header\n      0.99    correct handling of alpha in palette\n      0.98    TGA loader by lonesock; dynamically add loaders (untested)\n      0.97    jpeg errors on too large a file; also catch another malloc failure\n      0.96    fix detection of invalid v value - particleman@mollyrocket forum\n      0.95    during header scan, seek to markers in case of padding\n      0.94    STBI_NO_STDIO to disable stdio usage; rename all #defines the same\n      0.93    handle jpegtran output; verbose errors\n      0.92    read 4,8,16,24,32-bit BMP files of several formats\n      0.91    output 24-bit Windows 3.0 BMP files\n      0.90    fix a few more warnings; bump version number to approach 1.0\n      0.61    bugfixes due to Marc LeBlanc, Christopher Lloyd\n      0.60    fix compiling as c++\n      0.59    fix warnings: merge Dave Moore's -Wall fixes\n      0.58    fix bug: zlib uncompressed mode len/nlen was wrong endian\n      0.57    fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available\n      0.56    fix bug: zlib uncompressed mode len vs. nlen\n      0.55    fix bug: restart_interval not initialized to 0\n      0.54    allow NULL for 'int *comp'\n      0.53    fix bug in png 3->4; speedup png decoding\n      0.52    png handles req_comp=3,4 directly; minor cleanup; jpeg comments\n      0.51    obey req_comp requests, 1-component jpegs return as 1-component,\n              on 'test' only check type, not whether we support this variant\n      0.50  (2006-11-19)\n              first released version\n*/\n"
  },
  {
    "path": "nuklear.h",
    "content": "/*\n# Nuklear\n![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)\n\n## Contents\n1. About section\n2. Highlights section\n3. Features section\n4. Usage section\n    1. Flags section\n    2. Constants section\n    3. Dependencies section\n5. Example section\n6. API section\n    1. Context section\n    2. Input section\n    3. Drawing section\n    4. Window section\n    5. Layouting section\n    6. Groups section\n    7. Tree section\n    8. Properties section\n7. License section\n8. Changelog section\n9. Gallery section\n10. Credits section\n\n## About\nThis is a minimal state immediate mode graphical user interface toolkit\nwritten in ANSI C and licensed under public domain. It was designed as a simple\nembeddable user interface for application and does not have any dependencies,\na default renderbackend or OS window and input handling but instead provides a very modular\nlibrary approach by using simple input state for input and draw\ncommands describing primitive shapes as output. So instead of providing a\nlayered library that tries to abstract over a number of platform and\nrender backends it only focuses on the actual UI.\n\n## Highlights\n- Graphical user interface toolkit\n- Single header library\n- Written in C89 (a.k.a. ANSI C or ISO C90)\n- Small codebase (~18kLOC)\n- Focus on portability, efficiency and simplicity\n- No dependencies (not even the standard library if not wanted)\n- Fully skinnable and customizable\n- Low memory footprint with total memory control if needed or wanted\n- UTF-8 support\n- No global or hidden state\n- Customizable library modules (you can compile and use only what you need)\n- Optional font baker and vertex buffer output\n- [Code available on github](https://github.com/Immediate-Mode-UI/Nuklear/)\n\n## Features\n- Absolutely no platform dependent code\n- Memory management control ranging from/to\n    - Ease of use by allocating everything from standard library\n    - Control every byte of memory inside the library\n- Font handling control ranging from/to\n    - Use your own font implementation for everything\n    - Use this libraries internal font baking and handling API\n- Drawing output control ranging from/to\n    - Simple shapes for more high level APIs which already have drawing capabilities\n    - Hardware accessible anti-aliased vertex buffer output\n- Customizable colors and properties ranging from/to\n    - Simple changes to color by filling a simple color table\n    - Complete control with ability to use skinning to decorate widgets\n- Bendable UI library with widget ranging from/to\n    - Basic widgets like buttons, checkboxes, slider, ...\n    - Advanced widget like abstract comboboxes, contextual menus,...\n- Compile time configuration to only compile what you need\n    - Subset which can be used if you do not want to link or use the standard library\n- Can be easily modified to only update on user input instead of frame updates\n\n## Usage\nThis library is self contained in one single header file and can be used either\nin header only mode or in implementation mode. The header only mode is used\nby default when included and allows including this header in other headers\nand does not contain the actual implementation. <br /><br />\n\nThe implementation mode requires to define  the preprocessor macro\nNK_IMPLEMENTATION in *one* .c/.cpp file before #including this file, e.g.:\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C\n    #define NK_IMPLEMENTATION\n    #include \"nuklear.h\"\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAlso optionally define the symbols listed in the section \"OPTIONAL DEFINES\"\nbelow in header and implementation mode if you want to use additional functionality\nor need more control over the library.\n\n!!! WARNING\n    Every time nuklear is included define the same compiler flags. This very important not doing so could lead to compiler errors or even worse stack corruptions.\n\n### Flags\nFlag                            | Description\n--------------------------------|------------------------------------------\nNK_PRIVATE                      | If defined declares all functions as static, so they can only be accessed inside the file that contains the implementation\nNK_INCLUDE_FIXED_TYPES          | If defined it will include header `<stdint.h>` for fixed sized types otherwise nuklear tries to select the correct type. If that fails it will throw a compiler error and you have to select the correct types yourself.\nNK_INCLUDE_DEFAULT_ALLOCATOR    | If defined it will include header `<stdlib.h>` and provide additional functions to use this library without caring for memory allocation control and therefore ease memory management.\nNK_INCLUDE_STANDARD_IO          | If defined it will include header `<stdio.h>` and provide additional functions depending on file loading.\nNK_INCLUDE_STANDARD_VARARGS     | If defined it will include header <stdarg.h> and provide additional functions depending on file loading.\nNK_INCLUDE_STANDARD_BOOL        | If defined it will include header `<stdbool.h>` for nk_bool otherwise nuklear defines nk_bool as int.\nNK_INCLUDE_VERTEX_BUFFER_OUTPUT | Defining this adds a vertex draw command list backend to this library, which allows you to convert queue commands into vertex draw commands. This is mainly if you need a hardware accessible format for OpenGL, DirectX, Vulkan, Metal,...\nNK_INCLUDE_FONT_BAKING          | Defining this adds `stb_truetype` and `stb_rect_pack` implementation to this library and provides font baking and rendering. If you already have font handling or do not want to use this font handler you don't have to define it.\nNK_INCLUDE_DEFAULT_FONT         | Defining this adds the default font: ProggyClean.ttf into this library which can be loaded into a font atlas and allows using this library without having a truetype font\nNK_INCLUDE_COMMAND_USERDATA     | Defining this adds a userdata pointer into each command. Can be useful for example if you want to provide custom shaders depending on the used widget. Can be combined with the style structures.\nNK_BUTTON_TRIGGER_ON_RELEASE    | Different platforms require button clicks occurring either on buttons being pressed (up to down) or released (down to up). By default this library will react on buttons being pressed, but if you define this it will only trigger if a button is released.\nNK_ZERO_COMMAND_MEMORY          | Defining this will zero out memory for each drawing command added to a drawing queue (inside nk_command_buffer_push). Zeroing command memory is very useful for fast checking (using memcmp) if command buffers are equal and avoid drawing frames when nothing on screen has changed since previous frame.\nNK_UINT_DRAW_INDEX              | Defining this will set the size of vertex index elements when using NK_VERTEX_BUFFER_OUTPUT to 32bit instead of the default of 16bit\nNK_KEYSTATE_BASED_INPUT         | Define this if your backend uses key state for each frame rather than key press/release events\nNK_IS_WORD_BOUNDARY(c)          | Define this to a function macro that takes a single nk_rune (nk_uint) and returns true if it's a word separator. If not defined, uses the default definition (see nk_is_word_boundary())\n\n!!! WARNING\n    The following flags will pull in the standard C library:\n    - NK_INCLUDE_DEFAULT_ALLOCATOR\n    - NK_INCLUDE_STANDARD_IO\n    - NK_INCLUDE_STANDARD_VARARGS\n\n!!! WARNING\n    The following flags if defined need to be defined for both header and implementation:\n    - NK_INCLUDE_FIXED_TYPES\n    - NK_INCLUDE_DEFAULT_ALLOCATOR\n    - NK_INCLUDE_STANDARD_VARARGS\n    - NK_INCLUDE_STANDARD_BOOL\n    - NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n    - NK_INCLUDE_FONT_BAKING\n    - NK_INCLUDE_DEFAULT_FONT\n    - NK_INCLUDE_STANDARD_VARARGS\n    - NK_INCLUDE_COMMAND_USERDATA\n    - NK_UINT_DRAW_INDEX\n\n### Constants\nDefine                          | Description\n--------------------------------|---------------------------------------\nNK_BUFFER_DEFAULT_INITIAL_SIZE  | Initial buffer size allocated by all buffers while using the default allocator functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't want to allocate the default 4k memory then redefine it.\nNK_MAX_NUMBER_BUFFER            | Maximum buffer size for the conversion buffer between float and string Under normal circumstances this should be more than sufficient.\nNK_INPUT_MAX                    | Defines the max number of bytes which can be added as text input in one frame. Under normal circumstances this should be more than sufficient.\n\n!!! WARNING\n    The following constants if defined need to be defined for both header and implementation:\n    - NK_MAX_NUMBER_BUFFER\n    - NK_BUFFER_DEFAULT_INITIAL_SIZE\n    - NK_INPUT_MAX\n\n### Dependencies\nFunction    | Description\n------------|---------------------------------------------------------------\nNK_ASSERT   | If you don't define this, nuklear will use <assert.h> with assert().\nNK_MEMSET   | You can define this to 'memset' or your own memset implementation replacement. If not nuklear will use its own version.\nNK_MEMCPY   | You can define this to 'memcpy' or your own memcpy implementation replacement. If not nuklear will use its own version.\nNK_INV_SQRT | You can define this to your own inverse sqrt implementation replacement. If not nuklear will use its own slow and not highly accurate version.\nNK_SIN      | You can define this to 'sinf' or your own sine implementation replacement. If not nuklear will use its own approximation implementation.\nNK_COS      | You can define this to 'cosf' or your own cosine implementation replacement. If not nuklear will use its own approximation implementation.\nNK_STRTOD   | You can define this to `strtod` or your own string to double conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).\nNK_DTOA     | You can define this to `dtoa` or your own double to string conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).\nNK_VSNPRINTF| If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO` and want to be safe define this to `vsnprintf` on compilers supporting later versions of C or C++. By default nuklear will check for your stdlib version in C as well as compiler version in C++. if `vsnprintf` is available it will define it to `vsnprintf` directly. If not defined and if you have older versions of C or C++ it will be defined to `vsprintf` which is unsafe.\n\n!!! WARNING\n    The following dependencies will pull in the standard C library if not redefined:\n    - NK_ASSERT\n\n!!! WARNING\n    The following dependencies if defined need to be defined for both header and implementation:\n    - NK_ASSERT\n\n!!! WARNING\n    The following dependencies if defined need to be defined only for the implementation part:\n    - NK_MEMSET\n    - NK_MEMCPY\n    - NK_SQRT\n    - NK_SIN\n    - NK_COS\n    - NK_STRTOD\n    - NK_DTOA\n    - NK_VSNPRINTF\n\n## Example\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c\n// init gui state\nenum {EASY, HARD};\nstatic int op = EASY;\nstatic float value = 0.6f;\nstatic int i =  20;\nstruct nk_context ctx;\n\nnk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);\nif (nk_begin(&ctx, \"Show\", nk_rect(50, 50, 220, 220),\n    NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) {\n    // fixed widget pixel width\n    nk_layout_row_static(&ctx, 30, 80, 1);\n    if (nk_button_label(&ctx, \"button\")) {\n        // event handling\n    }\n\n    // fixed widget window ratio width\n    nk_layout_row_dynamic(&ctx, 30, 2);\n    if (nk_option_label(&ctx, \"easy\", op == EASY)) op = EASY;\n    if (nk_option_label(&ctx, \"hard\", op == HARD)) op = HARD;\n\n    // custom widget pixel width\n    nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);\n    {\n        nk_layout_row_push(&ctx, 50);\n        nk_label(&ctx, \"Volume:\", NK_TEXT_LEFT);\n        nk_layout_row_push(&ctx, 110);\n        nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);\n    }\n    nk_layout_row_end(&ctx);\n}\nnk_end(&ctx);\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n![](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)\n\n## API\n\n*/\n#ifndef NK_SINGLE_FILE\n  #define NK_SINGLE_FILE\n#endif\n\n/** \\file nuklear.h\n * \\brief main API and documentation file\n *\n * \\details\n */\n#ifndef NK_NUKLEAR_H_\n#define NK_NUKLEAR_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * ==============================================================\n *\n *                          CONSTANTS\n *\n * ===============================================================\n */\n\n#define NK_UNDEFINED (-1.0f)\n#define NK_UTF_INVALID 0xFFFD /**< internal invalid utf8 rune */\n#define NK_UTF_SIZE 4 /**< describes the number of bytes a glyph consists of*/\n#ifndef NK_INPUT_MAX\n  #define NK_INPUT_MAX 16\n#endif\n#ifndef NK_MAX_NUMBER_BUFFER\n  #define NK_MAX_NUMBER_BUFFER 64\n#endif\n#ifndef NK_SCROLLBAR_HIDING_TIMEOUT\n  #define NK_SCROLLBAR_HIDING_TIMEOUT 4.0f\n#endif\n/*\n * ==============================================================\n *\n *                          HELPER\n *\n * ===============================================================\n */\n\n#ifndef NK_API\n  #ifdef NK_PRIVATE\n    #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199409L))\n      #define NK_API static inline\n    #elif defined(__cplusplus)\n      #define NK_API static inline\n    #else\n      #define NK_API static\n    #endif\n  #else\n    #define NK_API extern\n  #endif\n#endif\n#ifndef NK_LIB\n  #ifdef NK_SINGLE_FILE\n    #define NK_LIB static\n  #else\n    #define NK_LIB extern\n  #endif\n#endif\n\n#define NK_INTERN static\n#define NK_STORAGE static\n#define NK_GLOBAL static\n\n#define NK_FLAG(x) (1 << (x))\n#define NK_STRINGIFY(x) #x\n#define NK_MACRO_STRINGIFY(x) NK_STRINGIFY(x)\n#define NK_STRING_JOIN_IMMEDIATE(arg1, arg2) arg1 ## arg2\n#define NK_STRING_JOIN_DELAY(arg1, arg2) NK_STRING_JOIN_IMMEDIATE(arg1, arg2)\n#define NK_STRING_JOIN(arg1, arg2) NK_STRING_JOIN_DELAY(arg1, arg2)\n\n#ifdef _MSC_VER\n  #define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__COUNTER__)\n#else\n  #define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__LINE__)\n#endif\n\n#ifndef NK_STATIC_ASSERT\n  #define NK_STATIC_ASSERT(exp) typedef char NK_UNIQUE_NAME(_dummy_array)[(exp)?1:-1]\n#endif\n\n#ifndef NK_FILE_LINE\n#ifdef _MSC_VER\n  #define NK_FILE_LINE __FILE__ \":\" NK_MACRO_STRINGIFY(__COUNTER__)\n#else\n  #define NK_FILE_LINE __FILE__ \":\" NK_MACRO_STRINGIFY(__LINE__)\n#endif\n#endif\n\n#define NK_MIN(a,b) ((a) < (b) ? (a) : (b))\n#define NK_MAX(a,b) ((a) < (b) ? (b) : (a))\n#define NK_CLAMP(i,v,x) (NK_MAX(NK_MIN(v,x), i))\n\n#ifdef NK_INCLUDE_STANDARD_VARARGS\n  #include <stdarg.h>\n  #if defined(_MSC_VER) && (_MSC_VER >= 1600) /* VS 2010 and above */\n    #include <sal.h>\n    #define NK_PRINTF_FORMAT_STRING _Printf_format_string_\n  #else\n    #define NK_PRINTF_FORMAT_STRING\n  #endif\n  #if defined(__GNUC__)\n    #define NK_PRINTF_VARARG_FUNC(fmtargnumber) __attribute__((format(__printf__, fmtargnumber, fmtargnumber+1)))\n    #define NK_PRINTF_VALIST_FUNC(fmtargnumber) __attribute__((format(__printf__, fmtargnumber, 0)))\n  #else\n    #define NK_PRINTF_VARARG_FUNC(fmtargnumber)\n    #define NK_PRINTF_VALIST_FUNC(fmtargnumber)\n  #endif\n#endif\n\n/*\n * ===============================================================\n *\n *                          BASIC\n *\n * ===============================================================\n */\n #ifdef NK_INCLUDE_FIXED_TYPES\n #include <stdint.h>\n #define NK_INT8 int8_t\n #define NK_UINT8 uint8_t\n #define NK_INT16 int16_t\n #define NK_UINT16 uint16_t\n #define NK_INT32 int32_t\n #define NK_UINT32 uint32_t\n #define NK_SIZE_TYPE uintptr_t\n #define NK_POINTER_TYPE uintptr_t\n#else\n  #ifndef NK_INT8\n    #define NK_INT8 signed char\n  #endif\n  #ifndef NK_UINT8\n    #define NK_UINT8 unsigned char\n  #endif\n  #ifndef NK_INT16\n    #define NK_INT16 signed short\n  #endif\n  #ifndef NK_UINT16\n    #define NK_UINT16 unsigned short\n  #endif\n  #ifndef NK_INT32\n    #if defined(_MSC_VER)\n      #define NK_INT32 __int32\n    #else\n      #define NK_INT32 signed int\n    #endif\n  #endif\n  #ifndef NK_UINT32\n    #if defined(_MSC_VER)\n      #define NK_UINT32 unsigned __int32\n    #else\n      #define NK_UINT32 unsigned int\n    #endif\n  #endif\n  #ifndef NK_SIZE_TYPE\n    #if defined(_WIN64) && defined(_MSC_VER)\n      #define NK_SIZE_TYPE unsigned __int64\n    #elif defined(_WIN64) && (defined(__MINGW64__) || defined(__clang__))\n      #define NK_SIZE_TYPE unsigned long long\n    #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)\n      #define NK_SIZE_TYPE unsigned __int32\n    #elif (defined(_WIN32) || defined(WIN32)) && (defined(__MINGW32__) || defined(__clang__))\n      #define NK_SIZE_TYPE unsigned long\n    #elif defined(__GNUC__) || defined(__clang__)\n      #if defined(__x86_64__) || defined(__ppc64__) || defined(__PPC64__) || defined(__aarch64__)\n        #define NK_SIZE_TYPE unsigned long\n      #else\n        #define NK_SIZE_TYPE unsigned int\n      #endif\n    #else\n      #define NK_SIZE_TYPE unsigned long\n    #endif\n  #endif\n  #ifndef NK_POINTER_TYPE\n    #if defined(_WIN64) && defined(_MSC_VER)\n      #define NK_POINTER_TYPE unsigned __int64\n    #elif defined(_WIN64) && (defined(__MINGW64__) || defined(__clang__))\n      #define NK_POINTER_TYPE unsigned long long\n    #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)\n      #define NK_POINTER_TYPE unsigned __int32\n    #elif (defined(_WIN32) || defined(WIN32)) && (defined(__MINGW32__) || defined(__clang__))\n      #define NK_POINTER_TYPE unsigned long\n    #elif defined(__GNUC__) || defined(__clang__)\n      #if defined(__x86_64__) || defined(__ppc64__) || defined(__PPC64__) || defined(__aarch64__)\n        #define NK_POINTER_TYPE unsigned long\n      #else\n        #define NK_POINTER_TYPE unsigned int\n      #endif\n    #else\n      #define NK_POINTER_TYPE unsigned long\n    #endif\n  #endif\n#endif\n\n/**< could be any type with semantic of standard bool, either equal or smaller than int */\n#ifndef NK_BOOL\n  #ifdef NK_INCLUDE_STANDARD_BOOL\n    #include <stdbool.h>\n    #define NK_BOOL bool\n  #else\n    #define NK_BOOL int\n  #endif\n#endif\n\ntypedef NK_INT8 nk_char;\ntypedef NK_UINT8 nk_uchar;\ntypedef NK_UINT8 nk_byte;\ntypedef NK_INT16 nk_short;\ntypedef NK_UINT16 nk_ushort;\ntypedef NK_INT32 nk_int;\ntypedef NK_UINT32 nk_uint;\ntypedef NK_SIZE_TYPE nk_size;\ntypedef NK_POINTER_TYPE nk_ptr;\ntypedef NK_BOOL nk_bool;\n\ntypedef nk_uint nk_hash;\ntypedef nk_uint nk_flags;\ntypedef nk_uint nk_rune;\n\n/* Make sure correct type size:\n * This will fire with a negative subscript error if the type sizes\n * are set incorrectly by the compiler, and compile out if not */\nNK_STATIC_ASSERT(sizeof(nk_short) == 2);\nNK_STATIC_ASSERT(sizeof(nk_ushort) == 2);\nNK_STATIC_ASSERT(sizeof(nk_uint) == 4);\nNK_STATIC_ASSERT(sizeof(nk_int) == 4);\nNK_STATIC_ASSERT(sizeof(nk_byte) == 1);\nNK_STATIC_ASSERT(sizeof(nk_flags) >= 4);\nNK_STATIC_ASSERT(sizeof(nk_rune) >= 4);\nNK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*));\nNK_STATIC_ASSERT(sizeof(nk_ptr) >= sizeof(void*));\nNK_STATIC_ASSERT(sizeof(nk_bool) <= sizeof(int));\n\n/* ============================================================================\n *\n *                                  API\n *\n * =========================================================================== */\nstruct nk_buffer;\nstruct nk_allocator;\nstruct nk_command_buffer;\nstruct nk_draw_command;\nstruct nk_convert_config;\nstruct nk_style_item;\nstruct nk_text_edit;\nstruct nk_draw_list;\nstruct nk_user_font;\nstruct nk_panel;\nstruct nk_context;\nstruct nk_draw_vertex_layout_element;\nstruct nk_style_button;\nstruct nk_style_toggle;\nstruct nk_style_selectable;\nstruct nk_style_slide;\nstruct nk_style_progress;\nstruct nk_style_scrollbar;\nstruct nk_style_edit;\nstruct nk_style_property;\nstruct nk_style_chart;\nstruct nk_style_combo;\nstruct nk_style_tab;\nstruct nk_style_window_header;\nstruct nk_style_window;\n\nenum {nk_false, nk_true};\nstruct nk_color {nk_byte r,g,b,a;};\nstruct nk_colorf {float r,g,b,a;};\nstruct nk_vec2 {float x,y;};\nstruct nk_vec2i {short x, y;};\nstruct nk_rect {float x,y,w,h;};\nstruct nk_recti {short x,y,w,h;};\ntypedef char nk_glyph[NK_UTF_SIZE];\ntypedef union {void *ptr; int id;} nk_handle;\nstruct nk_image {nk_handle handle; nk_ushort w, h; nk_ushort region[4];};\nstruct nk_nine_slice {struct nk_image img; nk_ushort l, t, r, b;};\nstruct nk_cursor {struct nk_image img; struct nk_vec2 size, offset;};\nstruct nk_scroll {nk_uint x, y;};\n\n/* Make sure the semantic of nk_true/nk_false is compatible with nk_bool */\nNK_STATIC_ASSERT(!((nk_bool)0) == !(nk_false));\nNK_STATIC_ASSERT(!((nk_bool)1) == !(nk_true));\n\nenum nk_heading         {NK_UP, NK_RIGHT, NK_DOWN, NK_LEFT};\nenum nk_button_behavior {NK_BUTTON_DEFAULT, NK_BUTTON_REPEATER};\nenum nk_modify          {NK_FIXED = nk_false, NK_MODIFIABLE = nk_true};\nenum nk_orientation     {NK_VERTICAL, NK_HORIZONTAL};\nenum nk_collapse_states {NK_MINIMIZED = nk_false, NK_MAXIMIZED = nk_true};\nenum nk_show_states     {NK_HIDDEN = nk_false, NK_SHOWN = nk_true};\nenum nk_chart_type      {NK_CHART_LINES, NK_CHART_COLUMN, NK_CHART_MAX};\nenum nk_chart_event     {NK_CHART_HOVERING = 0x01, NK_CHART_CLICKED = 0x02};\nenum nk_color_format    {NK_RGB, NK_RGBA};\nenum nk_popup_type      {NK_POPUP_STATIC, NK_POPUP_DYNAMIC};\nenum nk_layout_format   {NK_DYNAMIC, NK_STATIC};\nenum nk_tree_type       {NK_TREE_NODE, NK_TREE_TAB};\n\nenum nk_tooltip_pos {\n    NK_TOP_LEFT,\n    NK_TOP_CENTER,\n    NK_TOP_RIGHT,\n\n    NK_MIDDLE_LEFT,\n    NK_MIDDLE_CENTER,\n    NK_MIDDLE_RIGHT,\n\n    NK_BOTTOM_LEFT,\n    NK_BOTTOM_CENTER,\n    NK_BOTTOM_RIGHT\n};\n\ntypedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size);\ntypedef void (*nk_plugin_free)(nk_handle, void *old);\ntypedef nk_bool(*nk_plugin_filter)(const struct nk_text_edit*, nk_rune unicode);\ntypedef void(*nk_plugin_paste)(nk_handle, struct nk_text_edit*);\ntypedef void(*nk_plugin_copy)(nk_handle, const char*, int len);\n\nstruct nk_allocator {\n    nk_handle userdata;\n    nk_plugin_alloc alloc;\n    nk_plugin_free free;\n};\nenum nk_symbol_type {\n    NK_SYMBOL_NONE,\n    NK_SYMBOL_X,\n    NK_SYMBOL_UNDERSCORE,\n    NK_SYMBOL_CIRCLE_SOLID,\n    NK_SYMBOL_CIRCLE_OUTLINE,\n    NK_SYMBOL_RECT_SOLID,\n    NK_SYMBOL_RECT_OUTLINE,\n    NK_SYMBOL_TRIANGLE_UP,\n    NK_SYMBOL_TRIANGLE_DOWN,\n    NK_SYMBOL_TRIANGLE_LEFT,\n    NK_SYMBOL_TRIANGLE_RIGHT,\n    NK_SYMBOL_PLUS,\n    NK_SYMBOL_MINUS,\n    NK_SYMBOL_TRIANGLE_UP_OUTLINE,\n    NK_SYMBOL_TRIANGLE_DOWN_OUTLINE,\n    NK_SYMBOL_TRIANGLE_LEFT_OUTLINE,\n    NK_SYMBOL_TRIANGLE_RIGHT_OUTLINE,\n    NK_SYMBOL_MAX\n};\n/* =============================================================================\n *\n *                                  CONTEXT\n *\n * =============================================================================*/\n/**\n * \\page Context\n * Contexts are the main entry point and the majestro of nuklear and contain all required state.\n * They are used for window, memory, input, style, stack, commands and time management and need\n * to be passed into all nuklear GUI specific functions.\n *\n * # Usage\n * To use a context it first has to be initialized which can be achieved by calling\n * one of either `nk_init_default`, `nk_init_fixed`, `nk_init`, `nk_init_custom`.\n * Each takes in a font handle and a specific way of handling memory. Memory control\n * hereby ranges from standard library to just specifying a fixed sized block of memory\n * which nuklear has to manage itself from.\n *\n * ```c\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     // [...]\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n *\n * # Reference\n * Function            | Description\n * --------------------|-------------------------------------------------------\n * \\ref nk_init_default | Initializes context with standard library memory allocation (malloc,free)\n * \\ref nk_init_fixed   | Initializes context from single fixed size memory block\n * \\ref nk_init         | Initializes context with memory allocator callbacks for alloc and free\n * \\ref nk_init_custom  | Initializes context from two buffers. One for draw commands the other for window/panel/table allocations\n * \\ref nk_clear        | Called at the end of the frame to reset and prepare the context for the next frame\n * \\ref nk_free         | Shutdown and free all memory allocated inside the context\n * \\ref nk_set_user_data| Utility function to pass user data to draw command\n */\n\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\n\n/**\n * # nk_init_default\n * Initializes a `nk_context` struct with a default standard library allocator.\n * Should be used if you don't want to be bothered with memory management in nuklear.\n *\n * ```c\n * nk_bool nk_init_default(struct nk_context *ctx, const struct nk_user_font *font);\n * ```\n *\n * Parameter   | Description\n * ------------|---------------------------------------------------------------\n * \\param[in] ctx     | Must point to an either stack or heap allocated `nk_context` struct\n * \\param[in] font    | Must point to a previously initialized font handle for more info look at font documentation\n *\n * \\returns either `false(0)` on failure or `true(1)` on success.\n */\nNK_API nk_bool nk_init_default(struct nk_context*, const struct nk_user_font*);\n#endif\n/**\n * # nk_init_fixed\n * Initializes a `nk_context` struct from single fixed size memory block\n * Should be used if you want complete control over nuklear's memory management.\n * Especially recommended for system with little memory or systems with virtual memory.\n * For the later case you can just allocate for example 16MB of virtual memory\n * and only the required amount of memory will actually be committed.\n *\n * ```c\n * nk_bool nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size, const struct nk_user_font *font);\n * ```\n *\n * !!! Warning\n *     make sure the passed memory block is aligned correctly for `nk_draw_commands`.\n *\n * Parameter   | Description\n * ------------|--------------------------------------------------------------\n * \\param[in] ctx     | Must point to an either stack or heap allocated `nk_context` struct\n * \\param[in] memory  | Must point to a previously allocated memory block\n * \\param[in] size    | Must contain the total size of memory\n * \\param[in] font    | Must point to a previously initialized font handle for more info look at font documentation\n *\n * \\returns either `false(0)` on failure or `true(1)` on success.\n */\nNK_API nk_bool nk_init_fixed(struct nk_context*, void *memory, nk_size size, const struct nk_user_font*);\n\n/**\n * # nk_init\n * Initializes a `nk_context` struct with memory allocation callbacks for nuklear to allocate\n * memory from. Used internally for `nk_init_default` and provides a kitchen sink allocation\n * interface to nuklear. Can be useful for cases like monitoring memory consumption.\n *\n * ```c\n * nk_bool nk_init(struct nk_context *ctx, const struct nk_allocator *alloc, const struct nk_user_font *font);\n * ```\n *\n * Parameter   | Description\n * ------------|---------------------------------------------------------------\n * \\param[in] ctx     | Must point to an either stack or heap allocated `nk_context` struct\n * \\param[in] alloc   | Must point to a previously allocated memory allocator\n * \\param[in] font    | Must point to a previously initialized font handle for more info look at font documentation\n *\n * \\returns either `false(0)` on failure or `true(1)` on success.\n */\nNK_API nk_bool nk_init(struct nk_context*, const struct nk_allocator*, const struct nk_user_font*);\n\n/**\n * \\brief Initializes a `nk_context` struct from two different either fixed or growing buffers.\n *\n * \\details\n * The first buffer is for allocating draw commands while the second buffer is\n * used for allocating windows, panels and state tables.\n *\n * ```c\n * nk_bool nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font *font);\n * ```\n *\n * \\param[in] ctx    Must point to an either stack or heap allocated `nk_context` struct\n * \\param[in] cmds   Must point to a previously initialized memory buffer either fixed or dynamic to store draw commands into\n * \\param[in] pool   Must point to a previously initialized memory buffer either fixed or dynamic to store windows, panels and tables\n * \\param[in] font   Must point to a previously initialized font handle for more info look at font documentation\n *\n * \\returns either `false(0)` on failure or `true(1)` on success.\n */\nNK_API nk_bool nk_init_custom(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font*);\n\n/**\n * \\brief Resets the context state at the end of the frame.\n *\n * \\details\n * This includes mostly garbage collector tasks like removing windows or table\n * not called and therefore used anymore.\n *\n * ```c\n * void nk_clear(struct nk_context *ctx);\n * ```\n *\n * \\param[in] ctx  Must point to a previously initialized `nk_context` struct\n */\nNK_API void nk_clear(struct nk_context*);\n\n/**\n * \\brief Frees all memory allocated by nuklear; Not needed if context was initialized with `nk_init_fixed`.\n *\n * \\details\n * ```c\n * void nk_free(struct nk_context *ctx);\n * ```\n *\n * \\param[in] ctx  Must point to a previously initialized `nk_context` struct\n */\nNK_API void nk_free(struct nk_context*);\n\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n/**\n * \\brief Sets the currently passed userdata passed down into each draw command.\n *\n * \\details\n * ```c\n * void nk_set_user_data(struct nk_context *ctx, nk_handle data);\n * ```\n *\n * \\param[in] ctx Must point to a previously initialized `nk_context` struct\n * \\param[in] data  Handle with either pointer or index to be passed into every draw commands\n */\nNK_API void nk_set_user_data(struct nk_context*, nk_handle handle);\n#endif\n/* =============================================================================\n *\n *                                  INPUT\n *\n * =============================================================================*/\n/**\n * \\page Input\n *\n * The input API is responsible for holding the current input state composed of\n * mouse, key and text input states.\n * It is worth noting that no direct OS or window handling is done in nuklear.\n * Instead all input state has to be provided by platform specific code. This on one hand\n * expects more work from the user and complicates usage but on the other hand\n * provides simple abstraction over a big number of platforms, libraries and other\n * already provided functionality.\n *\n * ```c\n * nk_input_begin(&ctx);\n * while (GetEvent(&evt)) {\n *     if (evt.type == MOUSE_MOVE)\n *         nk_input_motion(&ctx, evt.motion.x, evt.motion.y);\n *     else if (evt.type == [...]) {\n *         // [...]\n *     }\n * } nk_input_end(&ctx);\n * ```\n *\n * # Usage\n * Input state needs to be provided to nuklear by first calling `nk_input_begin`\n * which resets internal state like delta mouse position and button transitions.\n * After `nk_input_begin` all current input state needs to be provided. This includes\n * mouse motion, button and key pressed and released, text input and scrolling.\n * Both event- or state-based input handling are supported by this API\n * and should work without problems. Finally after all input state has been\n * mirrored `nk_input_end` needs to be called to finish input process.\n *\n * ```c\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     Event evt;\n *     nk_input_begin(&ctx);\n *     while (GetEvent(&evt)) {\n *         if (evt.type == MOUSE_MOVE)\n *             nk_input_motion(&ctx, evt.motion.x, evt.motion.y);\n *         else if (evt.type == [...]) {\n *             // [...]\n *         }\n *     }\n *     nk_input_end(&ctx);\n *     // [...]\n *     nk_clear(&ctx);\n * } nk_free(&ctx);\n * ```\n *\n * # Reference\n * Function            | Description\n * --------------------|-------------------------------------------------------\n * \\ref nk_input_begin  | Begins the input mirroring process. Needs to be called before all other `nk_input_xxx` calls\n * \\ref nk_input_motion | Mirrors mouse cursor position\n * \\ref nk_input_key    | Mirrors key state with either pressed or released\n * \\ref nk_input_button | Mirrors mouse button state with either pressed or released\n * \\ref nk_input_scroll | Mirrors mouse scroll values\n * \\ref nk_input_char   | Adds a single ASCII text character into an internal text buffer\n * \\ref nk_input_glyph  | Adds a single multi-byte UTF-8 character into an internal text buffer\n * \\ref nk_input_unicode| Adds a single unicode rune into an internal text buffer\n * \\ref nk_input_end    | Ends the input mirroring process by calculating state changes. Don't call any `nk_input_xxx` function referenced above after this call\n */\n\nenum nk_keys {\n    NK_KEY_NONE,\n    NK_KEY_SHIFT,\n    NK_KEY_CTRL,\n    NK_KEY_DEL,\n    NK_KEY_ENTER,\n    NK_KEY_TAB,\n    NK_KEY_BACKSPACE,\n    NK_KEY_COPY,\n    NK_KEY_CUT,\n    NK_KEY_PASTE,\n    NK_KEY_UP,\n    NK_KEY_DOWN,\n    NK_KEY_LEFT,\n    NK_KEY_RIGHT,\n    /* Shortcuts: text field */\n    NK_KEY_TEXT_INSERT_MODE,\n    NK_KEY_TEXT_REPLACE_MODE,\n    NK_KEY_TEXT_RESET_MODE,\n    NK_KEY_TEXT_LINE_START,\n    NK_KEY_TEXT_LINE_END,\n    NK_KEY_TEXT_START,\n    NK_KEY_TEXT_END,\n    NK_KEY_TEXT_UNDO,\n    NK_KEY_TEXT_REDO,\n    NK_KEY_TEXT_SELECT_ALL,\n    NK_KEY_TEXT_WORD_LEFT,\n    NK_KEY_TEXT_WORD_RIGHT,\n    /* Shortcuts: scrollbar */\n    NK_KEY_SCROLL_START,\n    NK_KEY_SCROLL_END,\n    NK_KEY_SCROLL_DOWN,\n    NK_KEY_SCROLL_UP,\n    NK_KEY_MAX\n};\nenum nk_buttons {\n    NK_BUTTON_LEFT,\n    NK_BUTTON_MIDDLE,\n    NK_BUTTON_RIGHT,\n    NK_BUTTON_DOUBLE, /* Double click of the Left mouse button. */\n    NK_BUTTON_X1, /* Commonly used for \"Back\" in UI navigation. Mouse Button 4. */\n    NK_BUTTON_X2, /* Commonly used for \"Forward\" in UI navigation. Mouse Button 5. */\n    NK_BUTTON_MAX\n};\n\n/**\n * \\brief Begins the input mirroring process by resetting text, scroll\n * mouse, previous mouse position and movement as well as key state transitions.\n *\n * \\details\n * ```c\n * void nk_input_begin(struct nk_context*);\n * ```\n *\n * \\param[in] ctx Must point to a previously initialized `nk_context` struct\n */\nNK_API void nk_input_begin(struct nk_context*);\n\n/**\n * \\brief Mirrors current mouse position to nuklear\n *\n * \\details\n * ```c\n * void nk_input_motion(struct nk_context *ctx, int x, int y);\n * ```\n *\n * \\param[in] ctx   Must point to a previously initialized `nk_context` struct\n * \\param[in] x     Must hold an integer describing the current mouse cursor x-position\n * \\param[in] y     Must hold an integer describing the current mouse cursor y-position\n */\nNK_API void nk_input_motion(struct nk_context*, int x, int y);\n\n/**\n * \\brief Mirrors the state of a specific key to nuklear\n *\n * \\details\n * ```c\n * void nk_input_key(struct nk_context*, enum nk_keys key, nk_bool down);\n * ```\n *\n * \\param[in] ctx      Must point to a previously initialized `nk_context` struct\n * \\param[in] key      Must be any value specified in enum `nk_keys` that needs to be mirrored\n * \\param[in] down     Must be 0 for key is up and 1 for key is down\n */\nNK_API void nk_input_key(struct nk_context*, enum nk_keys, nk_bool down);\n\n/**\n * \\brief Mirrors the state of a specific mouse button to nuklear\n *\n * \\details\n * ```c\n * void nk_input_button(struct nk_context *ctx, enum nk_buttons btn, int x, int y, nk_bool down);\n * ```\n *\n * \\param[in] ctx     Must point to a previously initialized `nk_context` struct\n * \\param[in] btn     Must be any value specified in enum `nk_buttons` that needs to be mirrored\n * \\param[in] x       Must contain an integer describing mouse cursor x-position on click up/down\n * \\param[in] y       Must contain an integer describing mouse cursor y-position on click up/down\n * \\param[in] down    Must be 0 for key is up and 1 for key is down\n */\nNK_API void nk_input_button(struct nk_context*, enum nk_buttons, int x, int y, nk_bool down);\n\n/**\n * \\brief Copies the last mouse scroll value to nuklear.\n *\n * \\details\n * Is generally a scroll value. So does not have to come from mouse and could\n * also originate from balls, tracks, linear guide rails, or other programs.\n *\n * ```c\n * void nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val);\n * ```\n *\n * \\param[in] ctx     | Must point to a previously initialized `nk_context` struct\n * \\param[in] val     | vector with both X- as well as Y-scroll value\n */\nNK_API void nk_input_scroll(struct nk_context*, struct nk_vec2 val);\n\n/**\n * \\brief Copies a single ASCII character into an internal text buffer\n *\n * \\details\n * This is basically a helper function to quickly push ASCII characters into\n * nuklear.\n *\n * \\note\n *     Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`.\n *\n * ```c\n * void nk_input_char(struct nk_context *ctx, char c);\n * ```\n *\n * \\param[in] ctx     | Must point to a previously initialized `nk_context` struct\n * \\param[in] c       | Must be a single ASCII character preferable one that can be printed\n */\nNK_API void nk_input_char(struct nk_context*, char);\n\n/**\n * \\brief Converts an encoded unicode rune into UTF-8 and copies the result into an\n * internal text buffer.\n *\n * \\note\n *     Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`.\n *\n * ```c\n * void nk_input_glyph(struct nk_context *ctx, const nk_glyph g);\n * ```\n *\n * \\param[in] ctx     | Must point to a previously initialized `nk_context` struct\n * \\param[in] g       | UTF-32 unicode codepoint\n */\nNK_API void nk_input_glyph(struct nk_context*, const nk_glyph);\n\n/**\n * \\brief Converts a unicode rune into UTF-8 and copies the result\n * into an internal text buffer.\n *\n * \\details\n * \\note\n *     Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`.\n *\n * ```c\n * void nk_input_unicode(struct nk_context*, nk_rune rune);\n * ```\n *\n * \\param[in] ctx     | Must point to a previously initialized `nk_context` struct\n * \\param[in] rune    | UTF-32 unicode codepoint\n */\nNK_API void nk_input_unicode(struct nk_context*, nk_rune);\n\n/**\n * \\brief End the input mirroring process by resetting mouse grabbing\n * state to ensure the mouse cursor is not grabbed indefinitely.\n *\n * \\details\n * ```c\n * void nk_input_end(struct nk_context *ctx);\n * ```\n *\n * \\param[in] ctx     | Must point to a previously initialized `nk_context` struct\n */\nNK_API void nk_input_end(struct nk_context*);\n\n/* =============================================================================\n *\n *                                  DRAWING\n *\n * =============================================================================*/\n/**\n * \\page Drawing\n * This library was designed to be render backend agnostic so it does\n * not draw anything to screen directly. Instead all drawn shapes, widgets\n * are made of, are buffered into memory and make up a command queue.\n * Each frame therefore fills the command buffer with draw commands\n * that then need to be executed by the user and his own render backend.\n * After that the command buffer needs to be cleared and a new frame can be\n * started. It is probably important to note that the command buffer is the main\n * drawing API and the optional vertex buffer API only takes this format and\n * converts it into a hardware accessible format.\n *\n * # Usage\n * To draw all draw commands accumulated over a frame you need your own render\n * backend able to draw a number of 2D primitives. This includes at least\n * filled and stroked rectangles, circles, text, lines, triangles and scissors.\n * As soon as this criterion is met you can iterate over each draw command\n * and execute each draw command in a interpreter like fashion:\n *\n * ```c\n * const struct nk_command *cmd = 0;\n * nk_foreach(cmd, &ctx) {\n *     switch (cmd->type) {\n *     case NK_COMMAND_LINE:\n *         your_draw_line_function(...)\n *         break;\n *     case NK_COMMAND_RECT\n *         your_draw_rect_function(...)\n *         break;\n *     case //...:\n *         //[...]\n *     }\n * }\n * ```\n *\n * In program flow context draw commands need to be executed after input has been\n * gathered and the complete UI with windows and their contained widgets have\n * been executed and before calling `nk_clear` which frees all previously\n * allocated draw commands.\n *\n * ```c\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     Event evt;\n *     nk_input_begin(&ctx);\n *     while (GetEvent(&evt)) {\n *         if (evt.type == MOUSE_MOVE)\n *             nk_input_motion(&ctx, evt.motion.x, evt.motion.y);\n *         else if (evt.type == [...]) {\n *             [...]\n *         }\n *     }\n *     nk_input_end(&ctx);\n *     //\n *     // [...]\n *     //\n *     const struct nk_command *cmd = 0;\n *     nk_foreach(cmd, &ctx) {\n *     switch (cmd->type) {\n *     case NK_COMMAND_LINE:\n *         your_draw_line_function(...)\n *         break;\n *     case NK_COMMAND_RECT\n *         your_draw_rect_function(...)\n *         break;\n *     case ...:\n *         // [...]\n *     }\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n *\n * You probably noticed that you have to draw all of the UI each frame which is\n * quite wasteful. While the actual UI updating loop is quite fast rendering\n * without actually needing it is not. So there are multiple things you could do.\n *\n * First is only update on input. This of course is only an option if your\n * application only depends on the UI and does not require any outside calculations.\n * If you actually only update on input make sure to update the UI two times each\n * frame and call `nk_clear` directly after the first pass and only draw in\n * the second pass. In addition it is recommended to also add additional timers\n * to make sure the UI is not drawn more than a fixed number of frames per second.\n *\n * ```c\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     // [...wait for input ]\n *     // [...do two UI passes ...]\n *     do_ui(...)\n *     nk_clear(&ctx);\n *     do_ui(...)\n *     //\n *     // draw\n *     const struct nk_command *cmd = 0;\n *     nk_foreach(cmd, &ctx) {\n *     switch (cmd->type) {\n *     case NK_COMMAND_LINE:\n *         your_draw_line_function(...)\n *         break;\n *     case NK_COMMAND_RECT\n *         your_draw_rect_function(...)\n *         break;\n *     case ...:\n *         //[...]\n *     }\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n *\n * The second probably more applicable trick is to only draw if anything changed.\n * It is not really useful for applications with continuous draw loop but\n * quite useful for desktop applications. To actually get nuklear to only\n * draw on changes you first have to define `NK_ZERO_COMMAND_MEMORY` and\n * allocate a memory buffer that will store each unique drawing output.\n * After each frame you compare the draw command memory inside the library\n * with your allocated buffer by memcmp. If memcmp detects differences\n * you have to copy the command buffer into the allocated buffer\n * and then draw like usual (this example uses fixed memory but you could\n * use dynamically allocated memory).\n *\n * ```c\n * //[... other defines ...]\n * #define NK_ZERO_COMMAND_MEMORY\n * #include \"nuklear.h\"\n * //\n * // setup context\n * struct nk_context ctx;\n * void *last = calloc(1,64*1024);\n * void *buf = calloc(1,64*1024);\n * nk_init_fixed(&ctx, buf, 64*1024);\n * //\n * // loop\n * while (1) {\n *     // [...input...]\n *     // [...ui...]\n *     void *cmds = nk_buffer_memory(&ctx.memory);\n *     if (memcmp(cmds, last, ctx.memory.allocated)) {\n *         memcpy(last,cmds,ctx.memory.allocated);\n *         const struct nk_command *cmd = 0;\n *         nk_foreach(cmd, &ctx) {\n *             switch (cmd->type) {\n *             case NK_COMMAND_LINE:\n *                 your_draw_line_function(...)\n *                 break;\n *             case NK_COMMAND_RECT\n *                 your_draw_rect_function(...)\n *                 break;\n *             case ...:\n *                 // [...]\n *             }\n *         }\n *     }\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n *\n * Finally while using draw commands makes sense for higher abstracted platforms like\n * X11 and Win32 or drawing libraries it is often desirable to use graphics\n * hardware directly. Therefore it is possible to just define\n * `NK_INCLUDE_VERTEX_BUFFER_OUTPUT` which includes optional vertex output.\n * To access the vertex output you first have to convert all draw commands into\n * vertexes by calling `nk_convert` which takes in your preferred vertex format.\n * After successfully converting all draw commands just iterate over and execute all\n * vertex draw commands:\n *\n * ```c\n * // fill configuration\n * struct your_vertex\n * {\n *     float pos[2]; // important to keep it to 2 floats\n *     float uv[2];\n *     unsigned char col[4];\n * };\n * struct nk_convert_config cfg = {};\n * static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n *     {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, pos)},\n *     {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, uv)},\n *     {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct your_vertex, col)},\n *     {NK_VERTEX_LAYOUT_END}\n * };\n * cfg.shape_AA = NK_ANTI_ALIASING_ON;\n * cfg.line_AA = NK_ANTI_ALIASING_ON;\n * cfg.vertex_layout = vertex_layout;\n * cfg.vertex_size = sizeof(struct your_vertex);\n * cfg.vertex_alignment = NK_ALIGNOF(struct your_vertex);\n * cfg.circle_segment_count = 22;\n * cfg.curve_segment_count = 22;\n * cfg.arc_segment_count = 22;\n * cfg.global_alpha = 1.0f;\n * cfg.tex_null = dev->tex_null;\n * //\n * // setup buffers and convert\n * struct nk_buffer cmds, verts, idx;\n * nk_buffer_init_default(&cmds);\n * nk_buffer_init_default(&verts);\n * nk_buffer_init_default(&idx);\n * nk_convert(&ctx, &cmds, &verts, &idx, &cfg);\n * //\n * // draw\n * nk_draw_foreach(cmd, &ctx, &cmds) {\n * if (!cmd->elem_count) continue;\n *     //[...]\n * }\n * nk_buffer_free(&cms);\n * nk_buffer_free(&verts);\n * nk_buffer_free(&idx);\n * ```\n *\n * # Reference\n * Function            | Description\n * --------------------|-------------------------------------------------------\n * \\ref nk__begin       | Returns the first draw command in the context draw command list to be drawn\n * \\ref nk__next        | Increments the draw command iterator to the next command inside the context draw command list\n * \\ref nk_foreach      | Iterates over each draw command inside the context draw command list\n * \\ref nk_convert      | Converts from the abstract draw commands list into a hardware accessible vertex format\n * \\ref nk_draw_begin   | Returns the first vertex command in the context vertex draw list to be executed\n * \\ref nk__draw_next   | Increments the vertex command iterator to the next command inside the context vertex command list\n * \\ref nk__draw_end    | Returns the end of the vertex draw list\n * \\ref nk_draw_foreach | Iterates over each vertex draw command inside the vertex draw list\n */\n\nenum nk_anti_aliasing {NK_ANTI_ALIASING_OFF, NK_ANTI_ALIASING_ON};\nenum nk_convert_result {\n    NK_CONVERT_SUCCESS = 0,\n    NK_CONVERT_INVALID_PARAM = 1,\n    NK_CONVERT_COMMAND_BUFFER_FULL = NK_FLAG(1),\n    NK_CONVERT_VERTEX_BUFFER_FULL = NK_FLAG(2),\n    NK_CONVERT_ELEMENT_BUFFER_FULL = NK_FLAG(3)\n};\nstruct nk_draw_null_texture {\n    nk_handle texture; /**!< texture handle to a texture with a white pixel */\n    struct nk_vec2 uv; /**!< coordinates to a white pixel in the texture  */\n};\nstruct nk_convert_config {\n    float global_alpha;             /**!< global alpha value */\n    enum nk_anti_aliasing line_AA;  /**!< line anti-aliasing flag can be turned off if you are tight on memory */\n    enum nk_anti_aliasing shape_AA; /**!< shape anti-aliasing flag can be turned off if you are tight on memory */\n    unsigned circle_segment_count;  /**!< number of segments used for circles: default to 22 */\n    unsigned arc_segment_count;     /**!< number of segments used for arcs: default to 22 */\n    unsigned curve_segment_count;   /**!< number of segments used for curves: default to 22 */\n    struct nk_draw_null_texture tex_null; /**!< handle to texture with a white pixel for shape drawing */\n    const struct nk_draw_vertex_layout_element *vertex_layout; /**!< describes the vertex output format and packing */\n    nk_size vertex_size;      /**!< sizeof one vertex for vertex packing */\n    nk_size vertex_alignment; /**!< vertex alignment: Can be obtained by NK_ALIGNOF */\n};\n\n/**\n * \\brief Returns a draw command list iterator to iterate all draw\n * commands accumulated over one frame.\n *\n * \\details\n * ```c\n * const struct nk_command* nk__begin(struct nk_context*);\n * ```\n *\n * \\param[in] ctx     | must point to an previously initialized `nk_context` struct at the end of a frame\n *\n * \\returns draw command pointer pointing to the first command inside the draw command list\n */\nNK_API const struct nk_command* nk__begin(struct nk_context*);\n\n/**\n * \\brief Returns draw command pointer pointing to the next command inside the draw command list\n *\n * \\details\n * ```c\n * const struct nk_command* nk__next(struct nk_context*, const struct nk_command*);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct at the end of a frame\n * \\param[in] cmd     | Must point to an previously a draw command either returned by `nk__begin` or `nk__next`\n *\n * \\returns draw command pointer pointing to the next command inside the draw command list\n */\nNK_API const struct nk_command* nk__next(struct nk_context*, const struct nk_command*);\n\n/**\n * \\brief Iterates over each draw command inside the context draw command list\n *\n * ```c\n * #define nk_foreach(c, ctx)\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct at the end of a frame\n * \\param[in] cmd     | Command pointer initialized to NULL\n */\n#define nk_foreach(c, ctx) for((c) = nk__begin(ctx); (c) != 0; (c) = nk__next(ctx,c))\n\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n\n/**\n * \\brief Converts all internal draw commands into vertex draw commands and fills\n * three buffers with vertexes, vertex draw commands and vertex indices.\n *\n * \\details\n * The vertex format as well as some other configuration values have to be\n * configured by filling out a `nk_convert_config` struct.\n *\n * ```c\n * nk_flags nk_convert(struct nk_context *ctx, struct nk_buffer *cmds,\n *     struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*);\n * ```\n *\n * \\param[in] ctx      Must point to an previously initialized `nk_context` struct at the end of a frame\n * \\param[out] cmds     Must point to a previously initialized buffer to hold converted vertex draw commands\n * \\param[out] vertices Must point to a previously initialized buffer to hold all produced vertices\n * \\param[out] elements Must point to a previously initialized buffer to hold all produced vertex indices\n * \\param[in] config   Must point to a filled out `nk_config` struct to configure the conversion process\n *\n * \\returns one of enum nk_convert_result error codes\n *\n * Parameter                       | Description\n * --------------------------------|-----------------------------------------------------------\n * NK_CONVERT_SUCCESS              | Signals a successful draw command to vertex buffer conversion\n * NK_CONVERT_INVALID_PARAM        | An invalid argument was passed in the function call\n * NK_CONVERT_COMMAND_BUFFER_FULL  | The provided buffer for storing draw commands is full or failed to allocate more memory\n * NK_CONVERT_VERTEX_BUFFER_FULL   | The provided buffer for storing vertices is full or failed to allocate more memory\n * NK_CONVERT_ELEMENT_BUFFER_FULL  | The provided buffer for storing indices is full or failed to allocate more memory\n */\nNK_API nk_flags nk_convert(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*);\n\n/**\n * \\brief Returns a draw vertex command buffer iterator to iterate over the vertex draw command buffer\n *\n * \\details\n * ```c\n * const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct at the end of a frame\n * \\param[in] buf     | Must point to an previously by `nk_convert` filled out vertex draw command buffer\n *\n * \\returns vertex draw command pointer pointing to the first command inside the vertex draw command buffer\n */\nNK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*);\n\n/**\n\n * # # nk__draw_end\n * \\returns the vertex draw command at the end of the vertex draw command buffer\n *\n * ```c\n * const struct nk_draw_command* nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buf);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct at the end of a frame\n * \\param[in] buf     | Must point to an previously by `nk_convert` filled out vertex draw command buffer\n *\n * \\returns vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer\n\n */\nNK_API const struct nk_draw_command* nk__draw_end(const struct nk_context*, const struct nk_buffer*);\n\n/**\n * # # nk__draw_next\n * Increments the vertex draw command buffer iterator\n *\n * ```c\n * const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] cmd     | Must point to an previously either by `nk__draw_begin` or `nk__draw_next` returned vertex draw command\n * \\param[in] buf     | Must point to an previously by `nk_convert` filled out vertex draw command buffer\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct at the end of a frame\n *\n * \\returns vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer\n\n */\nNK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*);\n\n/**\n * # # nk_draw_foreach\n * Iterates over each vertex draw command inside a vertex draw command buffer\n *\n * ```c\n * #define nk_draw_foreach(cmd,ctx, b)\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] cmd     | `nk_draw_command`iterator set to NULL\n * \\param[in] buf     | Must point to an previously by `nk_convert` filled out vertex draw command buffer\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct at the end of a frame\n */\n\n#define nk_draw_foreach(cmd,ctx, b) for((cmd)=nk__draw_begin(ctx, b); (cmd)!=0; (cmd)=nk__draw_next(cmd, b, ctx))\n#endif\n\n/* =============================================================================\n *\n *                                  WINDOW\n *\n * =============================================================================*/\n/**\n * \\page Window\n * Windows are the main persistent state used inside nuklear and are life time\n * controlled by simply \"retouching\" (i.e.\\ calling) each window each frame.\n * All widgets inside nuklear can only be added inside the function pair `nk_begin_xxx`\n * and `nk_end`. Calling any widgets outside these two functions will result in an\n * assert in debug or no state change in release mode.<br /><br />\n *\n * Each window holds frame persistent state like position, size, flags, state tables,\n * and some garbage collected internal persistent widget state. Each window\n * is linked into a window stack list which determines the drawing and overlapping\n * order. The topmost window thereby is the currently active window.<br /><br />\n *\n * To change window position inside the stack occurs either automatically by\n * user input by being clicked on or programmatically by calling `nk_window_focus`.\n * Windows by default are visible unless explicitly being defined with flag\n * `NK_WINDOW_HIDDEN`, the user clicked the close button on windows with flag\n * `NK_WINDOW_CLOSABLE` or if a window was explicitly hidden by calling\n * `nk_window_show`. To explicitly close and destroy a window call `nk_window_close`.<br /><br />\n *\n * # Usage\n * To create and keep a window you have to call one of the two `nk_begin_xxx`\n * functions to start window declarations and `nk_end` at the end. Furthermore it\n * is recommended to check the return value of `nk_begin_xxx` and only process\n * widgets inside the window if the value is not 0. Either way you have to call\n * `nk_end` at the end of window declarations. Furthermore, do not attempt to\n * nest `nk_begin_xxx` calls which will hopefully result in an assert or if not\n * in a segmentation fault.\n *\n * ```c\n * if (nk_begin_xxx(...) {\n *     // [... widgets ...]\n * }\n * nk_end(ctx);\n * ```\n *\n * In the grand concept window and widget declarations need to occur after input\n * handling and before drawing to screen. Not doing so can result in higher\n * latency or at worst invalid behavior. Furthermore make sure that `nk_clear`\n * is called at the end of the frame. While nuklear's default platform backends\n * already call `nk_clear` for you if you write your own backend not calling\n * `nk_clear` can cause asserts or even worse undefined behavior.\n *\n * ```c\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     Event evt;\n *     nk_input_begin(&ctx);\n *     while (GetEvent(&evt)) {\n *         if (evt.type == MOUSE_MOVE)\n *             nk_input_motion(&ctx, evt.motion.x, evt.motion.y);\n *         else if (evt.type == [...]) {\n *             nk_input_xxx(...);\n *         }\n *     }\n *     nk_input_end(&ctx);\n *\n *     if (nk_begin_xxx(...) {\n *         //[...]\n *     }\n *     nk_end(ctx);\n *\n *     const struct nk_command *cmd = 0;\n *     nk_foreach(cmd, &ctx) {\n *     case NK_COMMAND_LINE:\n *         your_draw_line_function(...)\n *         break;\n *     case NK_COMMAND_RECT\n *         your_draw_rect_function(...)\n *         break;\n *     case //...:\n *         //[...]\n *     }\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n *\n * # Reference\n * Function                                 | Description\n * -----------------------------------------|----------------------------------------\n * \\ref nk_begin                            | Starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed\n * \\ref nk_begin_titled                     | Extended window start with separated title and identifier to allow multiple windows with same name but not title\n * \\ref nk_end                              | Needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup\n *\n * Function                                 | Description\n * -----------------------------------------|----------------------------------------\n * \\ref nk_window_find                      | Finds and returns the window with give name\n * \\ref nk_window_get_bounds                | Returns a rectangle with screen position and size of the currently processed window.\n * \\ref nk_window_get_position              | Returns the position of the currently processed window\n * \\ref nk_window_get_size                  | Returns the size with width and height of the currently processed window\n * \\ref nk_window_get_width                 | Returns the width of the currently processed window\n * \\ref nk_window_get_height                | Returns the height of the currently processed window\n * \\ref nk_window_get_panel                 | Returns the underlying panel which contains all processing state of the current window\n * \\ref nk_window_get_content_region        | Returns the position and size of the currently visible and non-clipped space inside the currently processed window\n * \\ref nk_window_get_content_region_min    | Returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window\n * \\ref nk_window_get_content_region_max    | Returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window\n * \\ref nk_window_get_content_region_size   | Returns the size of the currently visible and non-clipped space inside the currently processed window\n * \\ref nk_window_get_canvas                | Returns the draw command buffer. Can be used to draw custom widgets\n * \\ref nk_window_get_scroll                | Gets the scroll offset of the current window\n * \\ref nk_window_has_focus                 | Returns if the currently processed window is currently active\n * \\ref nk_window_is_collapsed              | Returns if the window with given name is currently minimized/collapsed\n * \\ref nk_window_is_closed                 | Returns if the currently processed window was closed\n * \\ref nk_window_is_hidden                 | Returns if the currently processed window was hidden\n * \\ref nk_window_is_active                 | Same as nk_window_has_focus for some reason\n * \\ref nk_window_is_hovered                | Returns if the currently processed window is currently being hovered by mouse\n * \\ref nk_window_is_any_hovered            | Return if any window currently hovered\n * \\ref nk_item_is_any_active               | Returns if any window or widgets is currently hovered or active\n *\n * Function                                 | Description\n * -----------------------------------------|----------------------------------------\n * \\ref nk_window_set_bounds                | Updates position and size of the currently processed window\n * \\ref nk_window_set_position              | Updates position of the currently process window\n * \\ref nk_window_set_size                  | Updates the size of the currently processed window\n * \\ref nk_window_set_focus                 | Set the currently processed window as active window\n * \\ref nk_window_set_scroll                | Sets the scroll offset of the current window\n *\n * Function                                 | Description\n * -----------------------------------------|----------------------------------------\n * \\ref nk_window_close                     | Closes the window with given window name which deletes the window at the end of the frame\n * \\ref nk_window_collapse                  | Collapses the window with given window name\n * \\ref nk_window_collapse_if               | Collapses the window with given window name if the given condition was met\n * \\ref nk_window_show                      | Hides a visible or reshows a hidden window\n * \\ref nk_window_show_if                   | Hides/shows a window depending on condition\n\n * # nk_panel_flags\n * Flag                        | Description\n * ----------------------------|----------------------------------------\n * NK_WINDOW_BORDER            | Draws a border around the window to visually separate window from the background\n * NK_WINDOW_MOVABLE           | The movable flag indicates that a window can be moved by user input or by dragging the window header\n * NK_WINDOW_SCALABLE          | The scalable flag indicates that a window can be scaled by user input by dragging a scaler icon at the button of the window\n * NK_WINDOW_CLOSABLE          | Adds a closable icon into the header\n * NK_WINDOW_MINIMIZABLE       | Adds a minimize icon into the header\n * NK_WINDOW_NO_SCROLLBAR      | Removes the scrollbar from the window\n * NK_WINDOW_TITLE             | Forces a header at the top at the window showing the title\n * NK_WINDOW_SCROLL_AUTO_HIDE  | Automatically hides the window scrollbar if no user interaction: also requires delta time in `nk_context` to be set each frame\n * NK_WINDOW_BACKGROUND        | Always keep window in the background\n * NK_WINDOW_SCALE_LEFT        | Puts window scaler in the left-bottom corner instead right-bottom\n * NK_WINDOW_NO_INPUT          | Prevents window of scaling, moving or getting focus\n *\n * # nk_collapse_states\n * State           | Description\n * ----------------|-----------------------------------------------------------\n * NK_MINIMIZED| UI section is collapsed and not visible until maximized\n * NK_MAXIMIZED| UI section is extended and visible until minimized\n */\n\nenum nk_panel_flags {\n    NK_WINDOW_BORDER            = NK_FLAG(0),\n    NK_WINDOW_MOVABLE           = NK_FLAG(1),\n    NK_WINDOW_SCALABLE          = NK_FLAG(2),\n    NK_WINDOW_CLOSABLE          = NK_FLAG(3),\n    NK_WINDOW_MINIMIZABLE       = NK_FLAG(4),\n    NK_WINDOW_NO_SCROLLBAR      = NK_FLAG(5),\n    NK_WINDOW_TITLE             = NK_FLAG(6),\n    NK_WINDOW_SCROLL_AUTO_HIDE  = NK_FLAG(7),\n    NK_WINDOW_BACKGROUND        = NK_FLAG(8),\n    NK_WINDOW_SCALE_LEFT        = NK_FLAG(9),\n    NK_WINDOW_NO_INPUT          = NK_FLAG(10)\n};\n\n/**\n * # # nk_begin\n * Starts a new window; needs to be called every frame for every\n * window (unless hidden) or otherwise the window gets removed\n *\n * ```c\n * nk_bool nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] title   | Window title and identifier. Needs to be persistent over frames to identify the window\n * \\param[in] bounds  | Initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame\n * \\param[in] flags   | Window flags defined in the nk_panel_flags section with a number of different window behaviors\n *\n * \\returns `true(1)` if the window can be filled up with widgets from this point\n * until `nk_end` or `false(0)` otherwise for example if minimized\n\n */\nNK_API nk_bool nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags);\n\n/**\n * # # nk_begin_titled\n * Extended window start with separated title and identifier to allow multiple\n * windows with same title but not name\n *\n * ```c\n * nk_bool nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Window identifier. Needs to be persistent over frames to identify the window\n * \\param[in] title   | Window title displayed inside header if flag `NK_WINDOW_TITLE` or either `NK_WINDOW_CLOSABLE` or `NK_WINDOW_MINIMIZED` was set\n * \\param[in] bounds  | Initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame\n * \\param[in] flags   | Window flags defined in the nk_panel_flags section with a number of different window behaviors\n *\n * \\returns `true(1)` if the window can be filled up with widgets from this point\n * until `nk_end` or `false(0)` otherwise for example if minimized\n\n */\nNK_API nk_bool nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags);\n\n/**\n * # # nk_end\n * Needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup.\n * All widget calls after this functions will result in asserts or no state changes\n *\n * ```c\n * void nk_end(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n\n */\nNK_API void nk_end(struct nk_context *ctx);\n\n/**\n * # # nk_window_find\n * Finds and returns a window from passed name\n *\n * ```c\n * struct nk_window *nk_window_find(struct nk_context *ctx, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Window identifier\n *\n * \\returns a `nk_window` struct pointing to the identified window or NULL if\n * no window with the given name was found\n */\nNK_API struct nk_window *nk_window_find(const struct nk_context *ctx, const char *name);\n\n/**\n * # # nk_window_get_bounds\n * \\returns a rectangle with screen position and size of the currently processed window\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * struct nk_rect nk_window_get_bounds(const struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns a `nk_rect` struct with window upper left window position and size\n\n */\nNK_API struct nk_rect nk_window_get_bounds(const struct nk_context *ctx);\n\n/**\n * # # nk_window_get_position\n * \\returns the position of the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * struct nk_vec2 nk_window_get_position(const struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns a `nk_vec2` struct with window upper left position\n\n */\nNK_API struct nk_vec2 nk_window_get_position(const struct nk_context *ctx);\n\n/**\n * # # nk_window_get_size\n * \\returns the size with width and height of the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * struct nk_vec2 nk_window_get_size(const struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns a `nk_vec2` struct with window width and height\n\n */\nNK_API struct nk_vec2 nk_window_get_size(const struct nk_context *ctx);\n\n/**\n * nk_window_get_width\n * \\returns the width of the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * float nk_window_get_width(const struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns the current window width\n */\nNK_API float nk_window_get_width(const struct nk_context *ctx);\n\n/**\n * # # nk_window_get_height\n * \\returns the height of the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * float nk_window_get_height(const struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns the current window height\n\n */\nNK_API float nk_window_get_height(const struct nk_context* ctx);\n\n/**\n * # # nk_window_get_panel\n * \\returns the underlying panel which contains all processing state of the current window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * !!! \\warning\n *     Do not keep the returned panel pointer around, it is only valid until `nk_end`\n * ```c\n * struct nk_panel* nk_window_get_panel(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns a pointer to window internal `nk_panel` state.\n\n */\nNK_API struct nk_panel* nk_window_get_panel(const struct nk_context* ctx);\n\n/**\n * # # nk_window_get_content_region\n * \\returns the position and size of the currently visible and non-clipped space\n * inside the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n *\n * ```c\n * struct nk_rect nk_window_get_content_region(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `nk_rect` struct with screen position and size (no scrollbar offset)\n * of the visible space inside the current window\n\n */\nNK_API struct nk_rect nk_window_get_content_region(const struct nk_context* ctx);\n\n/**\n * # # nk_window_get_content_region_min\n * \\returns the upper left position of the currently visible and non-clipped\n * space inside the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n *\n * ```c\n * struct nk_vec2 nk_window_get_content_region_min(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * returns `nk_vec2` struct with  upper left screen position (no scrollbar offset)\n * of the visible space inside the current window\n\n */\nNK_API struct nk_vec2 nk_window_get_content_region_min(const struct nk_context *ctx);\n\n/**\n * # # nk_window_get_content_region_max\n * \\returns the lower right screen position of the currently visible and\n * non-clipped space inside the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n *\n * ```c\n * struct nk_vec2 nk_window_get_content_region_max(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `nk_vec2` struct with lower right screen position (no scrollbar offset)\n * of the visible space inside the current window\n\n */\nNK_API struct nk_vec2 nk_window_get_content_region_max(const struct nk_context *ctx);\n\n/**\n * # # nk_window_get_content_region_size\n * \\returns the size of the currently visible and non-clipped space inside the\n * currently processed window\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n *\n * ```c\n * struct nk_vec2 nk_window_get_content_region_size(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `nk_vec2` struct with size the visible space inside the current window\n\n */\nNK_API struct nk_vec2 nk_window_get_content_region_size(const struct nk_context *ctx);\n\n/**\n * # # nk_window_get_canvas\n * \\returns the draw command buffer. Can be used to draw custom widgets\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * !!! \\warning\n *     Do not keep the returned command buffer pointer around it is only valid until `nk_end`\n *\n * ```c\n * struct nk_command_buffer* nk_window_get_canvas(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns a pointer to window internal `nk_command_buffer` struct used as\n * drawing canvas. Can be used to do custom drawing.\n */\nNK_API struct nk_command_buffer* nk_window_get_canvas(const struct nk_context* ctx);\n\n/**\n * # # nk_window_get_scroll\n * Gets the scroll offset for the current window\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n *\n * ```c\n * void nk_window_get_scroll(struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y);\n * ```\n *\n * Parameter    | Description\n * -------------|-----------------------------------------------------------\n * \\param[in] ctx      | Must point to an previously initialized `nk_context` struct\n * \\param[in] offset_x | A pointer to the x offset output (or NULL to ignore)\n * \\param[in] offset_y | A pointer to the y offset output (or NULL to ignore)\n\n */\nNK_API void nk_window_get_scroll(const struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y);\n\n/**\n * # # nk_window_has_focus\n * \\returns if the currently processed window is currently active\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * nk_bool nk_window_has_focus(const struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `false(0)` if current window is not active or `true(1)` if it is\n\n */\nNK_API nk_bool nk_window_has_focus(const struct nk_context *ctx);\n\n/**\n * # # nk_window_is_hovered\n * Return if the current window is being hovered\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * nk_bool nk_window_is_hovered(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `true(1)` if current window is hovered or `false(0)` otherwise\n\n */\nNK_API nk_bool nk_window_is_hovered(const struct nk_context *ctx);\n\n/**\n * # # nk_window_is_collapsed\n * \\returns if the window with given name is currently minimized/collapsed\n * ```c\n * nk_bool nk_window_is_collapsed(struct nk_context *ctx, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of window you want to check if it is collapsed\n *\n * \\returns `true(1)` if current window is minimized and `false(0)` if window not\n * found or is not minimized\n\n */\nNK_API nk_bool nk_window_is_collapsed(const struct nk_context *ctx, const char *name);\n\n/**\n * # # nk_window_is_closed\n * \\returns if the window with given name was closed by calling `nk_close`\n * ```c\n * nk_bool nk_window_is_closed(struct nk_context *ctx, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of window you want to check if it is closed\n *\n * \\returns `true(1)` if current window was closed or `false(0)` window not found or not closed\n\n */\nNK_API nk_bool nk_window_is_closed(const struct nk_context *ctx, const char* name);\n\n/**\n * # # nk_window_is_hidden\n * \\returns if the window with given name is hidden\n * ```c\n * nk_bool nk_window_is_hidden(struct nk_context *ctx, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of window you want to check if it is hidden\n *\n * \\returns `true(1)` if current window is hidden or `false(0)` window not found or visible\n\n */\nNK_API nk_bool nk_window_is_hidden(const struct nk_context *ctx, const char* name);\n\n/**\n * # # nk_window_is_active\n * Same as nk_window_has_focus for some reason\n * ```c\n * nk_bool nk_window_is_active(struct nk_context *ctx, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of window you want to check if it is active\n *\n * \\returns `true(1)` if current window is active or `false(0)` window not found or not active\n */\nNK_API nk_bool nk_window_is_active(const struct nk_context *ctx, const char* name);\n\n/**\n * # # nk_window_is_any_hovered\n * \\returns if the any window is being hovered\n * ```c\n * nk_bool nk_window_is_any_hovered(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `true(1)` if any window is hovered or `false(0)` otherwise\n */\nNK_API nk_bool nk_window_is_any_hovered(const struct nk_context *ctx);\n\n/**\n * # # nk_item_is_any_active\n * \\returns if the any window is being hovered or any widget is currently active.\n * Can be used to decide if input should be processed by UI or your specific input handling.\n * Example could be UI and 3D camera to move inside a 3D space.\n * ```c\n * nk_bool nk_item_is_any_active(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `true(1)` if any window is hovered or any item is active or `false(0)` otherwise\n\n */\nNK_API nk_bool nk_item_is_any_active(const struct nk_context *ctx);\n\n/**\n * # # nk_window_set_bounds\n * Updates position and size of window with passed in name\n * ```c\n * void nk_window_set_bounds(struct nk_context*, const char *name, struct nk_rect bounds);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to modify both position and size\n * \\param[in] bounds  | Must point to a `nk_rect` struct with the new position and size\n\n */\nNK_API void nk_window_set_bounds(struct nk_context *ctx, const char *name, struct nk_rect bounds);\n\n/**\n * # # nk_window_set_position\n * Updates position of window with passed name\n * ```c\n * void nk_window_set_position(struct nk_context*, const char *name, struct nk_vec2 pos);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to modify both position\n * \\param[in] pos     | Must point to a `nk_vec2` struct with the new position\n\n */\nNK_API void nk_window_set_position(struct nk_context *ctx, const char *name, struct nk_vec2 pos);\n\n/**\n * # # nk_window_set_size\n * Updates size of window with passed in name\n * ```c\n * void nk_window_set_size(struct nk_context*, const char *name, struct nk_vec2);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to modify both window size\n * \\param[in] size    | Must point to a `nk_vec2` struct with new window size\n\n */\nNK_API void nk_window_set_size(struct nk_context *ctx, const char *name, struct nk_vec2 size);\n\n/**\n * # # nk_window_set_focus\n * Sets the window with given name as active\n * ```c\n * void nk_window_set_focus(struct nk_context*, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to set focus on\n\n */\nNK_API void nk_window_set_focus(struct nk_context *ctx, const char *name);\n\n/**\n * # # nk_window_set_scroll\n * Sets the scroll offset for the current window\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n *\n * ```c\n * void nk_window_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y);\n * ```\n *\n * Parameter    | Description\n * -------------|-----------------------------------------------------------\n * \\param[in] ctx      | Must point to an previously initialized `nk_context` struct\n * \\param[in] offset_x | The x offset to scroll to\n * \\param[in] offset_y | The y offset to scroll to\n\n */\nNK_API void nk_window_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y);\n\n/**\n * # # nk_window_close\n * Closes a window and marks it for being freed at the end of the frame\n * ```c\n * void nk_window_close(struct nk_context *ctx, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to close\n\n */\nNK_API void nk_window_close(struct nk_context *ctx, const char *name);\n\n/**\n * # # nk_window_collapse\n * Updates collapse state of a window with given name\n * ```c\n * void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to close\n * \\param[in] state   | value out of nk_collapse_states section\n\n */\nNK_API void nk_window_collapse(struct nk_context *ctx, const char *name, enum nk_collapse_states state);\n\n/**\n * # # nk_window_collapse_if\n * Updates collapse state of a window with given name if given condition is met\n * ```c\n * void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to either collapse or maximize\n * \\param[in] state   | value out of nk_collapse_states section the window should be put into\n * \\param[in] cond    | condition that has to be met to actually commit the collapse state change\n\n */\nNK_API void nk_window_collapse_if(struct nk_context *ctx, const char *name, enum nk_collapse_states state, int cond);\n\n/**\n * # # nk_window_show\n * updates visibility state of a window with given name\n * ```c\n * void nk_window_show(struct nk_context*, const char *name, enum nk_show_states);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to either collapse or maximize\n * \\param[in] state   | state with either visible or hidden to modify the window with\n */\nNK_API void nk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states state);\n\n/**\n * # # nk_window_show_if\n * Updates visibility state of a window with given name if a given condition is met\n * ```c\n * void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to either hide or show\n * \\param[in] state   | state with either visible or hidden to modify the window with\n * \\param[in] cond    | condition that has to be met to actually commit the visibility state change\n\n */\nNK_API void nk_window_show_if(struct nk_context *ctx, const char *name, enum nk_show_states state, int cond);\n\n/**\n * # # nk_window_show_if\n * Line for visual separation. Draws a line with thickness determined by the current row height.\n * ```c\n * void nk_rule_horizontal(struct nk_context *ctx, struct nk_color color, nk_bool rounding)\n * ```\n *\n * Parameter       | Description\n * ----------------|-------------------------------------------------------\n * \\param[in] ctx         | Must point to an previously initialized `nk_context` struct\n * \\param[in] color       | Color of the horizontal line\n * \\param[in] rounding    | Whether or not to make the line round\n */\nNK_API void nk_rule_horizontal(struct nk_context *ctx, struct nk_color color, nk_bool rounding);\n\n/* =============================================================================\n *\n *                                  LAYOUT\n *\n * =============================================================================*/\n/**\n * \\page Layouting\n * Layouting in general describes placing widget inside a window with position and size.\n * While in this particular implementation there are five different APIs for layouting\n * each with different trade offs between control and ease of use. <br /><br />\n *\n * All layouting methods in this library are based around the concept of a row.\n * A row has a height the window content grows by and a number of columns and each\n * layouting method specifies how each widget is placed inside the row.\n * After a row has been allocated by calling a layouting functions and then\n * filled with widgets will advance an internal pointer over the allocated row. <br /><br />\n *\n * To actually define a layout you just call the appropriate layouting function\n * and each subsequent widget call will place the widget as specified. Important\n * here is that if you define more widgets then columns defined inside the layout\n * functions it will allocate the next row without you having to make another layouting call. <br /><br />\n *\n * Biggest limitation with using all these APIs outside the `nk_layout_space_xxx` API\n * is that you have to define the row height for each. However the row height\n * often depends on the height of the font. <br /><br />\n *\n * To fix that internally nuklear uses a minimum row height that is set to the\n * height plus padding of currently active font and overwrites the row height\n * value if zero. <br /><br />\n *\n * If you manually want to change the minimum row height then\n * use nk_layout_set_min_row_height, and use nk_layout_reset_min_row_height to\n * reset it back to be derived from font height. <br /><br />\n *\n * Also if you change the font in nuklear it will automatically change the minimum\n * row height for you and. This means if you change the font but still want\n * a minimum row height smaller than the font you have to repush your value. <br /><br />\n *\n * For actually more advanced UI I would even recommend using the `nk_layout_space_xxx`\n * layouting method in combination with a cassowary constraint solver (there are\n * some versions on github with permissive license model) to take over all control over widget\n * layouting yourself. However for quick and dirty layouting using all the other layouting\n * functions should be fine.\n *\n * # Usage\n * 1. __nk_layout_row_dynamic__<br /><br />\n *    The easiest layouting function is `nk_layout_row_dynamic`. It provides each\n *    widgets with same horizontal space inside the row and dynamically grows\n *    if the owning window grows in width. So the number of columns dictates\n *    the size of each widget dynamically by formula:\n *\n *    ```c\n *    widget_width = (window_width - padding - spacing) * (1/column_count)\n *    ```\n *\n *    Just like all other layouting APIs if you define more widget than columns this\n *    library will allocate a new row and keep all layouting parameters previously\n *    defined.\n *\n *    ```c\n *    if (nk_begin_xxx(...) {\n *        // first row with height: 30 composed of two widgets\n *        nk_layout_row_dynamic(&ctx, 30, 2);\n *        nk_widget(...);\n *        nk_widget(...);\n *        //\n *        // second row with same parameter as defined above\n *        nk_widget(...);\n *        nk_widget(...);\n *        //\n *        // third row uses 0 for height which will use auto layouting\n *        nk_layout_row_dynamic(&ctx, 0, 2);\n *        nk_widget(...);\n *        nk_widget(...);\n *    }\n *    nk_end(...);\n *    ```\n *\n * 2. __nk_layout_row_static__<br /><br />\n *    Another easy layouting function is `nk_layout_row_static`. It provides each\n *    widget with same horizontal pixel width inside the row and does not grow\n *    if the owning window scales smaller or bigger.\n *\n *    ```c\n *    if (nk_begin_xxx(...) {\n *        // first row with height: 30 composed of two widgets with width: 80\n *        nk_layout_row_static(&ctx, 30, 80, 2);\n *        nk_widget(...);\n *        nk_widget(...);\n *        //\n *        // second row with same parameter as defined above\n *        nk_widget(...);\n *        nk_widget(...);\n *        //\n *        // third row uses 0 for height which will use auto layouting\n *        nk_layout_row_static(&ctx, 0, 80, 2);\n *        nk_widget(...);\n *        nk_widget(...);\n *    }\n *    nk_end(...);\n *    ```\n *\n * 3. __nk_layout_row_xxx__<br /><br />\n *    A little bit more advanced layouting API are functions `nk_layout_row_begin`,\n *    `nk_layout_row_push` and `nk_layout_row_end`. They allow to directly\n *    specify each column pixel or window ratio in a row. It supports either\n *    directly setting per column pixel width or widget window ratio but not\n *    both. Furthermore it is a immediate mode API so each value is directly\n *    pushed before calling a widget. Therefore the layout is not automatically\n *    repeating like the last two layouting functions.\n *\n *    ```c\n *    if (nk_begin_xxx(...) {\n *        // first row with height: 25 composed of two widgets with width 60 and 40\n *        nk_layout_row_begin(ctx, NK_STATIC, 25, 2);\n *        nk_layout_row_push(ctx, 60);\n *        nk_widget(...);\n *        nk_layout_row_push(ctx, 40);\n *        nk_widget(...);\n *        nk_layout_row_end(ctx);\n *        //\n *        // second row with height: 25 composed of two widgets with window ratio 0.25 and 0.75\n *        nk_layout_row_begin(ctx, NK_DYNAMIC, 25, 2);\n *        nk_layout_row_push(ctx, 0.25f);\n *        nk_widget(...);\n *        nk_layout_row_push(ctx, 0.75f);\n *        nk_widget(...);\n *        nk_layout_row_end(ctx);\n *        //\n *        // third row with auto generated height: composed of two widgets with window ratio 0.25 and 0.75\n *        nk_layout_row_begin(ctx, NK_DYNAMIC, 0, 2);\n *        nk_layout_row_push(ctx, 0.25f);\n *        nk_widget(...);\n *        nk_layout_row_push(ctx, 0.75f);\n *        nk_widget(...);\n *        nk_layout_row_end(ctx);\n *    }\n *    nk_end(...);\n *    ```\n *\n * 4. __nk_layout_row__<br /><br />\n *    The array counterpart to API nk_layout_row_xxx is the single nk_layout_row\n *    functions. Instead of pushing either pixel or window ratio for every widget\n *    it allows to define it by array. The trade of for less control is that\n *    `nk_layout_row` is automatically repeating. Otherwise the behavior is the\n *    same.\n *\n *    ```c\n *    if (nk_begin_xxx(...) {\n *        // two rows with height: 30 composed of two widgets with width 60 and 40\n *        const float ratio[] = {60,40};\n *        nk_layout_row(ctx, NK_STATIC, 30, 2, ratio);\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *        //\n *        // two rows with height: 30 composed of two widgets with window ratio 0.25 and 0.75\n *        const float ratio[] = {0.25, 0.75};\n *        nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio);\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *        //\n *        // two rows with auto generated height composed of two widgets with window ratio 0.25 and 0.75\n *        const float ratio[] = {0.25, 0.75};\n *        nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio);\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *    }\n *    nk_end(...);\n *    ```\n *\n * 5. __nk_layout_row_template_xxx__<br /><br />\n *    The most complex and second most flexible API is a simplified flexbox version without\n *    line wrapping and weights for dynamic widgets. It is an immediate mode API but\n *    unlike `nk_layout_row_xxx` it has auto repeat behavior and needs to be called\n *    before calling the templated widgets.\n *    The row template layout has three different per widget size specifier. The first\n *    one is the `nk_layout_row_template_push_static`  with fixed widget pixel width.\n *    They do not grow if the row grows and will always stay the same.\n *    The second size specifier is `nk_layout_row_template_push_variable`\n *    which defines a minimum widget size but it also can grow if more space is available\n *    not taken by other widgets.\n *    Finally there are dynamic widgets with `nk_layout_row_template_push_dynamic`\n *    which are completely flexible and unlike variable widgets can even shrink\n *    to zero if not enough space is provided.\n *\n *    ```c\n *    if (nk_begin_xxx(...) {\n *        // two rows with height: 30 composed of three widgets\n *        nk_layout_row_template_begin(ctx, 30);\n *        nk_layout_row_template_push_dynamic(ctx);\n *        nk_layout_row_template_push_variable(ctx, 80);\n *        nk_layout_row_template_push_static(ctx, 80);\n *        nk_layout_row_template_end(ctx);\n *        //\n *        // first row\n *        nk_widget(...); // dynamic widget can go to zero if not enough space\n *        nk_widget(...); // variable widget with min 80 pixel but can grow bigger if enough space\n *        nk_widget(...); // static widget with fixed 80 pixel width\n *        //\n *        // second row same layout\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *    }\n *    nk_end(...);\n *    ```\n *\n * 6. __nk_layout_space_xxx__<br /><br />\n *    Finally the most flexible API directly allows you to place widgets inside the\n *    window. The space layout API is an immediate mode API which does not support\n *    row auto repeat and directly sets position and size of a widget. Position\n *    and size hereby can be either specified as ratio of allocated space or\n *    allocated space local position and pixel size. Since this API is quite\n *    powerful there are a number of utility functions to get the available space\n *    and convert between local allocated space and screen space.\n *\n *    ```c\n *    if (nk_begin_xxx(...) {\n *        // static row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered)\n *        nk_layout_space_begin(ctx, NK_STATIC, 500, INT_MAX);\n *        nk_layout_space_push(ctx, nk_rect(0,0,150,200));\n *        nk_widget(...);\n *        nk_layout_space_push(ctx, nk_rect(200,200,100,200));\n *        nk_widget(...);\n *        nk_layout_space_end(ctx);\n *        //\n *        // dynamic row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered)\n *        nk_layout_space_begin(ctx, NK_DYNAMIC, 500, INT_MAX);\n *        nk_layout_space_push(ctx, nk_rect(0.5,0.5,0.1,0.1));\n *        nk_widget(...);\n *        nk_layout_space_push(ctx, nk_rect(0.7,0.6,0.1,0.1));\n *        nk_widget(...);\n *    }\n *    nk_end(...);\n *    ```\n *\n * # Reference\n * Function                                     | Description\n * ---------------------------------------------|------------------------------------\n * \\ref nk_layout_set_min_row_height            | Set the currently used minimum row height to a specified value\n * \\ref nk_layout_reset_min_row_height          | Resets the currently used minimum row height to font height\n * \\ref nk_layout_widget_bounds                 | Calculates current width a static layout row can fit inside a window\n * \\ref nk_layout_ratio_from_pixel              | Utility functions to calculate window ratio from pixel size\n * \\ref nk_layout_row_dynamic                   | Current layout is divided into n same sized growing columns\n * \\ref nk_layout_row_static                    | Current layout is divided into n same fixed sized columns\n * \\ref nk_layout_row_begin                     | Starts a new row with given height and number of columns\n * \\ref nk_layout_row_push                      | Pushes another column with given size or window ratio\n * \\ref nk_layout_row_end                       | Finished previously started row\n * \\ref nk_layout_row                           | Specifies row columns in array as either window ratio or size\n * \\ref nk_layout_row_template_begin            | Begins the row template declaration\n * \\ref nk_layout_row_template_push_dynamic     | Adds a dynamic column that dynamically grows and can go to zero if not enough space\n * \\ref nk_layout_row_template_push_variable    | Adds a variable column that dynamically grows but does not shrink below specified pixel width\n * \\ref nk_layout_row_template_push_static      | Adds a static column that does not grow and will always have the same size\n * \\ref nk_layout_row_template_end              | Marks the end of the row template\n * \\ref nk_layout_space_begin                   | Begins a new layouting space that allows to specify each widgets position and size\n * \\ref nk_layout_space_push                    | Pushes position and size of the next widget in own coordinate space either as pixel or ratio\n * \\ref nk_layout_space_end                     | Marks the end of the layouting space\n * \\ref nk_layout_space_bounds                  | Callable after nk_layout_space_begin and returns total space allocated\n * \\ref nk_layout_space_to_screen               | Converts vector from nk_layout_space coordinate space into screen space\n * \\ref nk_layout_space_to_local                | Converts vector from screen space into nk_layout_space coordinates\n * \\ref nk_layout_space_rect_to_screen          | Converts rectangle from nk_layout_space coordinate space into screen space\n * \\ref nk_layout_space_rect_to_local           | Converts rectangle from screen space into nk_layout_space coordinates\n */\n\n\n\nenum nk_widget_align {\n    NK_WIDGET_ALIGN_LEFT        = 0x01,\n    NK_WIDGET_ALIGN_CENTERED    = 0x02,\n    NK_WIDGET_ALIGN_RIGHT       = 0x04,\n    NK_WIDGET_ALIGN_TOP         = 0x08,\n    NK_WIDGET_ALIGN_MIDDLE      = 0x10,\n    NK_WIDGET_ALIGN_BOTTOM      = 0x20\n};\nenum nk_widget_alignment {\n    NK_WIDGET_LEFT        = NK_WIDGET_ALIGN_MIDDLE|NK_WIDGET_ALIGN_LEFT,\n    NK_WIDGET_CENTERED    = NK_WIDGET_ALIGN_MIDDLE|NK_WIDGET_ALIGN_CENTERED,\n    NK_WIDGET_RIGHT       = NK_WIDGET_ALIGN_MIDDLE|NK_WIDGET_ALIGN_RIGHT\n};\n\n/**\n * Sets the currently used minimum row height.\n * !!! \\warning\n *     The passed height needs to include both your preferred row height\n *     as well as padding. No internal padding is added.\n *\n * ```c\n * void nk_layout_set_min_row_height(struct nk_context*, float height);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] height  | New minimum row height to be used for auto generating the row height\n */\nNK_API void nk_layout_set_min_row_height(struct nk_context*, float height);\n\n/**\n * Reset the currently used minimum row height back to `font_height + text_padding + padding`\n * ```c\n * void nk_layout_reset_min_row_height(struct nk_context*);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n */\nNK_API void nk_layout_reset_min_row_height(struct nk_context*);\n\n/**\n * \\brief Returns the width of the next row allocate by one of the layouting functions\n *\n * \\details\n * ```c\n * struct nk_rect nk_layout_widget_bounds(struct nk_context*);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n *\n * \\return `nk_rect` with both position and size of the next row\n */\nNK_API struct nk_rect nk_layout_widget_bounds(const struct nk_context *ctx);\n\n/**\n * \\brief Utility functions to calculate window ratio from pixel size\n *\n * \\details\n * ```c\n * float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] pixel   | Pixel_width to convert to window ratio\n *\n * \\returns `nk_rect` with both position and size of the next row\n */\nNK_API float nk_layout_ratio_from_pixel(const struct nk_context *ctx, float pixel_width);\n\n/**\n * \\brief Sets current row layout to share horizontal space\n * between @cols number of widgets evenly. Once called all subsequent widget\n * calls greater than @cols will allocate a new row with same layout.\n *\n * \\details\n * ```c\n * void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] height  | Holds height of each widget in row or zero for auto layouting\n * \\param[in] columns | Number of widget inside row\n */\nNK_API void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols);\n\n/**\n * \\brief Sets current row layout to fill @cols number of widgets\n * in row with same @item_width horizontal size. Once called all subsequent widget\n * calls greater than @cols will allocate a new row with same layout.\n *\n * \\details\n * ```c\n * void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] height  | Holds height of each widget in row or zero for auto layouting\n * \\param[in] width   | Holds pixel width of each widget in the row\n * \\param[in] columns | Number of widget inside row\n */\nNK_API void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols);\n\n/**\n * \\brief Starts a new dynamic or fixed row with given height and columns.\n *\n * \\details\n * ```c\n * void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] fmt     | either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns\n * \\param[in] height  | holds height of each widget in row or zero for auto layouting\n * \\param[in] columns | Number of widget inside row\n */\nNK_API void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols);\n\n/**\n * \\breif Specifies either window ratio or width of a single column\n *\n * \\details\n * ```c\n * void nk_layout_row_push(struct nk_context*, float value);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] value   | either a window ratio or fixed width depending on @fmt in previous `nk_layout_row_begin` call\n */\nNK_API void nk_layout_row_push(struct nk_context*, float value);\n\n/**\n * \\brief Finished previously started row\n *\n * \\details\n * ```c\n * void nk_layout_row_end(struct nk_context*);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n */\nNK_API void nk_layout_row_end(struct nk_context*);\n\n/**\n * \\brief Specifies row columns in array as either window ratio or size\n *\n * \\details\n * ```c\n * void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] fmt     | Either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns\n * \\param[in] height  | Holds height of each widget in row or zero for auto layouting\n * \\param[in] columns | Number of widget inside row\n */\nNK_API void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio);\n\n/**\n * # # nk_layout_row_template_begin\n * Begins the row template declaration\n * ```c\n * void nk_layout_row_template_begin(struct nk_context*, float row_height);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] height  | Holds height of each widget in row or zero for auto layouting\n */\nNK_API void nk_layout_row_template_begin(struct nk_context*, float row_height);\n\n/**\n * # # nk_layout_row_template_push_dynamic\n * Adds a dynamic column that dynamically grows and can go to zero if not enough space\n * ```c\n * void nk_layout_row_template_push_dynamic(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] height  | Holds height of each widget in row or zero for auto layouting\n */\nNK_API void nk_layout_row_template_push_dynamic(struct nk_context*);\n\n/**\n * # # nk_layout_row_template_push_variable\n * Adds a variable column that dynamically grows but does not shrink below specified pixel width\n * ```c\n * void nk_layout_row_template_push_variable(struct nk_context*, float min_width);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] width   | Holds the minimum pixel width the next column must always be\n */\nNK_API void nk_layout_row_template_push_variable(struct nk_context*, float min_width);\n\n/**\n * # # nk_layout_row_template_push_static\n * Adds a static column that does not grow and will always have the same size\n * ```c\n * void nk_layout_row_template_push_static(struct nk_context*, float width);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] width   | Holds the absolute pixel width value the next column must be\n */\nNK_API void nk_layout_row_template_push_static(struct nk_context*, float width);\n\n/**\n * # # nk_layout_row_template_end\n * Marks the end of the row template\n * ```c\n * void nk_layout_row_template_end(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n */\nNK_API void nk_layout_row_template_end(struct nk_context*);\n\n/**\n * # # nk_layout_space_begin\n * Begins a new layouting space that allows to specify each widgets position and size.\n * ```c\n * void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] fmt     | Either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns\n * \\param[in] height  | Holds height of each widget in row or zero for auto layouting\n * \\param[in] columns | Number of widgets inside row\n */\nNK_API void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count);\n\n/**\n * # # nk_layout_space_push\n * Pushes position and size of the next widget in own coordinate space either as pixel or ratio\n * ```c\n * void nk_layout_space_push(struct nk_context *ctx, struct nk_rect bounds);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n * \\param[in] bounds  | Position and size in laoyut space local coordinates\n */\nNK_API void nk_layout_space_push(struct nk_context*, struct nk_rect bounds);\n\n/**\n * # # nk_layout_space_end\n * Marks the end of the layout space\n * ```c\n * void nk_layout_space_end(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n */\nNK_API void nk_layout_space_end(struct nk_context*);\n\n/**\n * # # nk_layout_space_bounds\n * Utility function to calculate total space allocated for `nk_layout_space`\n * ```c\n * struct nk_rect nk_layout_space_bounds(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n *\n * \\returns `nk_rect` holding the total space allocated\n */\nNK_API struct nk_rect nk_layout_space_bounds(const struct nk_context *ctx);\n\n/**\n * # # nk_layout_space_to_screen\n * Converts vector from nk_layout_space coordinate space into screen space\n * ```c\n * struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n * \\param[in] vec     | Position to convert from layout space into screen coordinate space\n *\n * \\returns transformed `nk_vec2` in screen space coordinates\n */\nNK_API struct nk_vec2 nk_layout_space_to_screen(const struct nk_context* ctx, struct nk_vec2 vec);\n\n/**\n * # # nk_layout_space_to_local\n * Converts vector from layout space into screen space\n * ```c\n * struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n * \\param[in] vec     | Position to convert from screen space into layout coordinate space\n *\n * \\returns transformed `nk_vec2` in layout space coordinates\n */\nNK_API struct nk_vec2 nk_layout_space_to_local(const struct nk_context *ctx, struct nk_vec2 vec);\n\n/**\n * # # nk_layout_space_rect_to_screen\n * Converts rectangle from screen space into layout space\n * ```c\n * struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n * \\param[in] bounds  | Rectangle to convert from layout space into screen space\n *\n * \\returns transformed `nk_rect` in screen space coordinates\n */\nNK_API struct nk_rect nk_layout_space_rect_to_screen(const struct nk_context *ctx, struct nk_rect bounds);\n\n/**\n * # # nk_layout_space_rect_to_local\n * Converts rectangle from layout space into screen space\n * ```c\n * struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n * \\param[in] bounds  | Rectangle to convert from layout space into screen space\n *\n * \\returns transformed `nk_rect` in layout space coordinates\n */\nNK_API struct nk_rect nk_layout_space_rect_to_local(const struct nk_context *ctx, struct nk_rect bounds);\n\n/**\n * # # nk_spacer\n * Spacer is a dummy widget that consumes space as usual but doesn't draw anything\n * ```c\n * void nk_spacer(struct nk_context* );\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n *\n */\nNK_API void nk_spacer(struct nk_context *ctx);\n\n\n/* =============================================================================\n *\n *                                  GROUP\n *\n * =============================================================================*/\n/**\n * \\page Groups\n * Groups are basically windows inside windows. They allow to subdivide space\n * in a window to layout widgets as a group. Almost all more complex widget\n * layouting requirements can be solved using groups and basic layouting\n * fuctionality. Groups just like windows are identified by an unique name and\n * internally keep track of scrollbar offsets by default. However additional\n * versions are provided to directly manage the scrollbar.\n *\n * # Usage\n * To create a group you have to call one of the three `nk_group_begin_xxx`\n * functions to start group declarations and `nk_group_end` at the end. Furthermore it\n * is required to check the return value of `nk_group_begin_xxx` and only process\n * widgets inside the window if the value is not 0.\n * Nesting groups is possible and even encouraged since many layouting schemes\n * can only be achieved by nesting. Groups, unlike windows, need `nk_group_end`\n * to be only called if the corresponding `nk_group_begin_xxx` call does not return 0:\n *\n * ```c\n * if (nk_group_begin_xxx(ctx, ...) {\n *     // [... widgets ...]\n *     nk_group_end(ctx);\n * }\n * ```\n *\n * In the grand concept groups can be called after starting a window\n * with `nk_begin_xxx` and before calling `nk_end`:\n *\n * ```c\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     // Input\n *     Event evt;\n *     nk_input_begin(&ctx);\n *     while (GetEvent(&evt)) {\n *         if (evt.type == MOUSE_MOVE)\n *             nk_input_motion(&ctx, evt.motion.x, evt.motion.y);\n *         else if (evt.type == [...]) {\n *             nk_input_xxx(...);\n *         }\n *     }\n *     nk_input_end(&ctx);\n *     //\n *     // Window\n *     if (nk_begin_xxx(...) {\n *         // [...widgets...]\n *         nk_layout_row_dynamic(...);\n *         if (nk_group_begin_xxx(ctx, ...) {\n *             //[... widgets ...]\n *             nk_group_end(ctx);\n *         }\n *     }\n *     nk_end(ctx);\n *     //\n *     // Draw\n *     const struct nk_command *cmd = 0;\n *     nk_foreach(cmd, &ctx) {\n *     switch (cmd->type) {\n *     case NK_COMMAND_LINE:\n *         your_draw_line_function(...)\n *         break;\n *     case NK_COMMAND_RECT\n *         your_draw_rect_function(...)\n *         break;\n *     case ...:\n *         // [...]\n *     }\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n * # Reference\n * Function                        | Description\n * --------------------------------|-------------------------------------------\n * \\ref nk_group_begin                  | Start a new group with internal scrollbar handling\n * \\ref nk_group_begin_titled           | Start a new group with separated name and title and internal scrollbar handling\n * \\ref nk_group_end                    | Ends a group. Should only be called if nk_group_begin returned non-zero\n * \\ref nk_group_scrolled_offset_begin  | Start a new group with manual separated handling of scrollbar x- and y-offset\n * \\ref nk_group_scrolled_begin         | Start a new group with manual scrollbar handling\n * \\ref nk_group_scrolled_end           | Ends a group with manual scrollbar handling. Should only be called if nk_group_begin returned non-zero\n * \\ref nk_group_get_scroll             | Gets the scroll offset for the given group\n * \\ref nk_group_set_scroll             | Sets the scroll offset for the given group\n */\n\n /**\n * \\brief Starts a new widget group. Requires a previous layouting function to specify a pos/size.\n * ```c\n * nk_bool nk_group_begin(struct nk_context*, const char *title, nk_flags);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] title   | Must be an unique identifier for this group that is also used for the group header\n * \\param[in] flags   | Window flags defined in the nk_panel_flags section with a number of different group behaviors\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_group_begin(struct nk_context*, const char *title, nk_flags);\n\n /**\n * \\brief Starts a new widget group. Requires a previous layouting function to specify a pos/size.\n * ```c\n * nk_bool nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] id      | Must be an unique identifier for this group\n * \\param[in] title   | Group header title\n * \\param[in] flags   | Window flags defined in the nk_panel_flags section with a number of different group behaviors\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags);\n\n/**\n * # # nk_group_end\n * Ends a widget group\n * ```c\n * void nk_group_end(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n */\nNK_API void nk_group_end(struct nk_context*);\n\n/**\n * # # nk_group_scrolled_offset_begin\n * starts a new widget group. requires a previous layouting function to specify\n * a size. Does not keep track of scrollbar.\n * ```c\n * nk_bool nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] x_offset| Scrollbar x-offset to offset all widgets inside the group horizontally.\n * \\param[in] y_offset| Scrollbar y-offset to offset all widgets inside the group vertically\n * \\param[in] title   | Window unique group title used to both identify and display in the group header\n * \\param[in] flags   | Window flags from the nk_panel_flags section\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags);\n\n/**\n * # # nk_group_scrolled_begin\n * Starts a new widget group. requires a previous\n * layouting function to specify a size. Does not keep track of scrollbar.\n * ```c\n * nk_bool nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] off     | Both x- and y- scroll offset. Allows for manual scrollbar control\n * \\param[in] title   | Window unique group title used to both identify and display in the group header\n * \\param[in] flags   | Window flags from nk_panel_flags section\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags);\n\n/**\n * # # nk_group_scrolled_end\n * Ends a widget group after calling nk_group_scrolled_offset_begin or nk_group_scrolled_begin.\n * ```c\n * void nk_group_scrolled_end(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n */\nNK_API void nk_group_scrolled_end(struct nk_context*);\n\n/**\n * # # nk_group_get_scroll\n * Gets the scroll position of the given group.\n * ```c\n * void nk_group_get_scroll(struct nk_context*, const char *id, nk_uint *x_offset, nk_uint *y_offset);\n * ```\n *\n * Parameter    | Description\n * -------------|-----------------------------------------------------------\n * \\param[in] ctx      | Must point to an previously initialized `nk_context` struct\n * \\param[in] id       | The id of the group to get the scroll position of\n * \\param[in] x_offset | A pointer to the x offset output (or NULL to ignore)\n * \\param[in] y_offset | A pointer to the y offset output (or NULL to ignore)\n */\nNK_API void nk_group_get_scroll(struct nk_context*, const char *id, nk_uint *x_offset, nk_uint *y_offset);\n\n/**\n * # # nk_group_set_scroll\n * Sets the scroll position of the given group.\n * ```c\n * void nk_group_set_scroll(struct nk_context*, const char *id, nk_uint x_offset, nk_uint y_offset);\n * ```\n *\n * Parameter    | Description\n * -------------|-----------------------------------------------------------\n * \\param[in] ctx      | Must point to an previously initialized `nk_context` struct\n * \\param[in] id       | The id of the group to scroll\n * \\param[in] x_offset | The x offset to scroll to\n * \\param[in] y_offset | The y offset to scroll to\n */\nNK_API void nk_group_set_scroll(struct nk_context*, const char *id, nk_uint x_offset, nk_uint y_offset);\n\n/* =============================================================================\n *\n *                                  TREE\n *\n * =============================================================================*/\n/**\n * \\page Tree\n * Trees represent two different concept. First the concept of a collapsible\n * UI section that can be either in a hidden or visible state. They allow the UI\n * user to selectively minimize the current set of visible UI to comprehend.\n * The second concept are tree widgets for visual UI representation of trees.<br /><br />\n *\n * Trees thereby can be nested for tree representations and multiple nested\n * collapsible UI sections. All trees are started by calling of the\n * `nk_tree_xxx_push_tree` functions and ended by calling one of the\n * `nk_tree_xxx_pop_xxx()` functions. Each starting functions takes a title label\n * and optionally an image to be displayed and the initial collapse state from\n * the nk_collapse_states section.<br /><br />\n *\n * The runtime state of the tree is either stored outside the library by the caller\n * or inside which requires a unique ID. The unique ID can either be generated\n * automatically from `__FILE__` and `__LINE__` with function `nk_tree_push`,\n * by `__FILE__` and a user provided ID generated for example by loop index with\n * function `nk_tree_push_id` or completely provided from outside by user with\n * function `nk_tree_push_hashed`.\n *\n * # Usage\n * To create a tree you have to call one of the seven `nk_tree_xxx_push_xxx`\n * functions to start a collapsible UI section and `nk_tree_xxx_pop` to mark the\n * end.\n * Each starting function will either return `false(0)` if the tree is collapsed\n * or hidden and therefore does not need to be filled with content or `true(1)`\n * if visible and required to be filled.\n *\n * !!! Note\n *     The tree header does not require and layouting function and instead\n *     calculates a auto height based on the currently used font size\n *\n * The tree ending functions only need to be called if the tree content is\n * actually visible. So make sure the tree push function is guarded by `if`\n * and the pop call is only taken if the tree is visible.\n *\n * ```c\n * if (nk_tree_push(ctx, NK_TREE_TAB, \"Tree\", NK_MINIMIZED)) {\n *     nk_layout_row_dynamic(...);\n *     nk_widget(...);\n *     nk_tree_pop(ctx);\n * }\n * ```\n *\n * # Reference\n * Function                    | Description\n * ----------------------------|-------------------------------------------\n * nk_tree_push                | Start a collapsible UI section with internal state management\n * nk_tree_push_id             | Start a collapsible UI section with internal state management callable in a look\n * nk_tree_push_hashed         | Start a collapsible UI section with internal state management with full control over internal unique ID use to store state\n * nk_tree_image_push          | Start a collapsible UI section with image and label header\n * nk_tree_image_push_id       | Start a collapsible UI section with image and label header and internal state management callable in a look\n * nk_tree_image_push_hashed   | Start a collapsible UI section with image and label header and internal state management with full control over internal unique ID use to store state\n * nk_tree_pop                 | Ends a collapsible UI section\n * nk_tree_state_push          | Start a collapsible UI section with external state management\n * nk_tree_state_image_push    | Start a collapsible UI section with image and label header and external state management\n * nk_tree_state_pop           | Ends a collapsabale UI section\n *\n * # nk_tree_type\n * Flag            | Description\n * ----------------|----------------------------------------\n * NK_TREE_NODE    | Highlighted tree header to mark a collapsible UI section\n * NK_TREE_TAB     | Non-highlighted tree header closer to tree representations\n */\n\n/**\n * # # nk_tree_push\n * Starts a collapsible UI section with internal state management\n * !!! \\warning\n *     To keep track of the runtime tree collapsible state this function uses\n *     defines `__FILE__` and `__LINE__` to generate a unique ID. If you want\n *     to call this function in a loop please use `nk_tree_push_id` or\n *     `nk_tree_push_hashed` instead.\n *\n * ```c\n * #define nk_tree_push(ctx, type, title, state)\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Initial tree state value out of nk_collapse_states\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\n#define nk_tree_push(ctx, type, title, state) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__)\n\n/**\n * # # nk_tree_push_id\n * Starts a collapsible UI section with internal state management callable in a look\n * ```c\n * #define nk_tree_push_id(ctx, type, title, state, id)\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Initial tree state value out of nk_collapse_states\n * \\param[in] id      | Loop counter index if this function is called in a loop\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\n#define nk_tree_push_id(ctx, type, title, state, id) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id)\n\n/**\n * # # nk_tree_push_hashed\n * Start a collapsible UI section with internal state management with full\n * control over internal unique ID used to store state\n * ```c\n * nk_bool nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Initial tree state value out of nk_collapse_states\n * \\param[in] hash    | Memory block or string to generate the ID from\n * \\param[in] len     | Size of passed memory block or string in __hash__\n * \\param[in] seed    | Seeding value if this function is called in a loop or default to `0`\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);\n\n/**\n * # # nk_tree_image_push\n * Start a collapsible UI section with image and label header\n * !!! \\warning\n *     To keep track of the runtime tree collapsible state this function uses\n *     defines `__FILE__` and `__LINE__` to generate a unique ID. If you want\n *     to call this function in a loop please use `nk_tree_image_push_id` or\n *     `nk_tree_image_push_hashed` instead.\n *\n * ```c\n * #define nk_tree_image_push(ctx, type, img, title, state)\n * ```\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] img     | Image to display inside the header on the left of the label\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Initial tree state value out of nk_collapse_states\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\n#define nk_tree_image_push(ctx, type, img, title, state) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__)\n\n/**\n * # # nk_tree_image_push_id\n * Start a collapsible UI section with image and label header and internal state\n * management callable in a look\n *\n * ```c\n * #define nk_tree_image_push_id(ctx, type, img, title, state, id)\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] img     | Image to display inside the header on the left of the label\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Initial tree state value out of nk_collapse_states\n * \\param[in] id      | Loop counter index if this function is called in a loop\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\n#define nk_tree_image_push_id(ctx, type, img, title, state, id) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id)\n\n/**\n * # # nk_tree_image_push_hashed\n * Start a collapsible UI section with internal state management with full\n * control over internal unique ID used to store state\n * ```c\n * nk_bool nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] img     | Image to display inside the header on the left of the label\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Initial tree state value out of nk_collapse_states\n * \\param[in] hash    | Memory block or string to generate the ID from\n * \\param[in] len     | Size of passed memory block or string in __hash__\n * \\param[in] seed    | Seeding value if this function is called in a loop or default to `0`\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);\n\n/**\n * # # nk_tree_pop\n * Ends a collapsabale UI section\n * ```c\n * void nk_tree_pop(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx`\n */\nNK_API void nk_tree_pop(struct nk_context*);\n\n/**\n * # # nk_tree_state_push\n * Start a collapsible UI section with external state management\n * ```c\n * nk_bool nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx`\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Persistent state to update\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state);\n\n/**\n * # # nk_tree_state_image_push\n * Start a collapsible UI section with image and label header and external state management\n * ```c\n * nk_bool nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx`\n * \\param[in] img     | Image to display inside the header on the left of the label\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Persistent state to update\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state);\n\n/**\n * # # nk_tree_state_pop\n * Ends a collapsabale UI section\n * ```c\n * void nk_tree_state_pop(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx`\n */\nNK_API void nk_tree_state_pop(struct nk_context*);\n\n#define nk_tree_element_push(ctx, type, title, state, sel) nk_tree_element_push_hashed(ctx, type, title, state, sel, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__)\n#define nk_tree_element_push_id(ctx, type, title, state, sel, id) nk_tree_element_push_hashed(ctx, type, title, state, sel, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id)\nNK_API nk_bool nk_tree_element_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, nk_bool *selected, const char *hash, int len, int seed);\nNK_API nk_bool nk_tree_element_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, nk_bool *selected, const char *hash, int len,int seed);\nNK_API void nk_tree_element_pop(struct nk_context*);\n\n/* =============================================================================\n *\n *                                  LIST VIEW\n *\n * ============================================================================= */\nstruct nk_list_view {\n/* public: */\n    int begin, end, count;\n/* private: */\n    int total_height;\n    struct nk_context *ctx;\n    nk_uint *scroll_pointer;\n    nk_uint scroll_value;\n};\nNK_API nk_bool nk_list_view_begin(struct nk_context*, struct nk_list_view *out, const char *id, nk_flags, int row_height, int row_count);\nNK_API void nk_list_view_end(struct nk_list_view*);\n/* =============================================================================\n *\n *                                  WIDGET\n *\n * ============================================================================= */\nenum nk_widget_layout_states {\n    NK_WIDGET_INVALID, /**< The widget cannot be seen and is completely out of view */\n    NK_WIDGET_VALID,   /**< The widget is completely inside the window and can be updated and drawn */\n    NK_WIDGET_ROM,     /**< The widget is partially visible and cannot be updated */\n    NK_WIDGET_DISABLED /**< The widget is manually disabled and acts like NK_WIDGET_ROM */\n};\nenum nk_widget_states {\n    NK_WIDGET_STATE_MODIFIED    = NK_FLAG(1),\n    NK_WIDGET_STATE_INACTIVE    = NK_FLAG(2), /**!< widget is neither active nor hovered */\n    NK_WIDGET_STATE_ENTERED     = NK_FLAG(3), /**!< widget has been hovered on the current frame */\n    NK_WIDGET_STATE_HOVER       = NK_FLAG(4), /**!< widget is being hovered */\n    NK_WIDGET_STATE_ACTIVED     = NK_FLAG(5),/**!< widget is currently activated */\n    NK_WIDGET_STATE_LEFT        = NK_FLAG(6), /**!< widget is from this frame on not hovered anymore */\n    NK_WIDGET_STATE_HOVERED     = NK_WIDGET_STATE_HOVER|NK_WIDGET_STATE_MODIFIED, /**!< widget is being hovered */\n    NK_WIDGET_STATE_ACTIVE      = NK_WIDGET_STATE_ACTIVED|NK_WIDGET_STATE_MODIFIED /**!< widget is currently activated */\n};\nNK_API enum nk_widget_layout_states nk_widget(struct nk_rect*, const struct nk_context*);\nNK_API enum nk_widget_layout_states nk_widget_fitting(struct nk_rect*, const struct nk_context*, struct nk_vec2);\nNK_API struct nk_rect nk_widget_bounds(const struct nk_context*);\nNK_API struct nk_vec2 nk_widget_position(const struct nk_context*);\nNK_API struct nk_vec2 nk_widget_size(const struct nk_context*);\nNK_API float nk_widget_width(const struct nk_context*);\nNK_API float nk_widget_height(const struct nk_context*);\nNK_API nk_bool nk_widget_is_hovered(const struct nk_context*);\nNK_API nk_bool nk_widget_is_mouse_clicked(const struct nk_context*, enum nk_buttons);\nNK_API nk_bool nk_widget_has_mouse_click_down(const struct nk_context*, enum nk_buttons, nk_bool down);\nNK_API void nk_spacing(struct nk_context*, int cols);\nNK_API void nk_widget_disable_begin(struct nk_context* ctx);\nNK_API void nk_widget_disable_end(struct nk_context* ctx);\n/* =============================================================================\n *\n *                                  TEXT\n *\n * ============================================================================= */\nenum nk_text_align {\n    NK_TEXT_ALIGN_LEFT        = 0x01,\n    NK_TEXT_ALIGN_CENTERED    = 0x02,\n    NK_TEXT_ALIGN_RIGHT       = 0x04,\n    NK_TEXT_ALIGN_TOP         = 0x08,\n    NK_TEXT_ALIGN_MIDDLE      = 0x10,\n    NK_TEXT_ALIGN_BOTTOM      = 0x20\n};\nenum nk_text_alignment {\n    NK_TEXT_LEFT        = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_LEFT,\n    NK_TEXT_CENTERED    = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_CENTERED,\n    NK_TEXT_RIGHT       = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_RIGHT\n};\nNK_API void nk_text(struct nk_context*, const char*, int, nk_flags);\nNK_API void nk_text_colored(struct nk_context*, const char*, int, nk_flags, struct nk_color);\nNK_API void nk_text_wrap(struct nk_context*, const char*, int);\nNK_API void nk_text_wrap_colored(struct nk_context*, const char*, int, struct nk_color);\nNK_API void nk_label(struct nk_context*, const char*, nk_flags align);\nNK_API void nk_label_colored(struct nk_context*, const char*, nk_flags align, struct nk_color);\nNK_API void nk_label_wrap(struct nk_context*, const char*);\nNK_API void nk_label_colored_wrap(struct nk_context*, const char*, struct nk_color);\nNK_API void nk_image(struct nk_context*, struct nk_image);\nNK_API void nk_image_color(struct nk_context*, struct nk_image, struct nk_color);\n#ifdef NK_INCLUDE_STANDARD_VARARGS\nNK_API void nk_labelf(struct nk_context*, nk_flags, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(3);\nNK_API void nk_labelf_colored(struct nk_context*, nk_flags, struct nk_color, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(4);\nNK_API void nk_labelf_wrap(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(2);\nNK_API void nk_labelf_colored_wrap(struct nk_context*, struct nk_color, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(3);\nNK_API void nk_labelfv(struct nk_context*, nk_flags, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(3);\nNK_API void nk_labelfv_colored(struct nk_context*, nk_flags, struct nk_color, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(4);\nNK_API void nk_labelfv_wrap(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2);\nNK_API void nk_labelfv_colored_wrap(struct nk_context*, struct nk_color, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(3);\nNK_API void nk_value_bool(struct nk_context*, const char *prefix, int);\nNK_API void nk_value_int(struct nk_context*, const char *prefix, int);\nNK_API void nk_value_uint(struct nk_context*, const char *prefix, unsigned int);\nNK_API void nk_value_float(struct nk_context*, const char *prefix, float);\nNK_API void nk_value_color_byte(struct nk_context*, const char *prefix, struct nk_color);\nNK_API void nk_value_color_float(struct nk_context*, const char *prefix, struct nk_color);\nNK_API void nk_value_color_hex(struct nk_context*, const char *prefix, struct nk_color);\n#endif\n/* =============================================================================\n *\n *                                  BUTTON\n *\n * ============================================================================= */\nNK_API nk_bool nk_button_text(struct nk_context*, const char *title, int len);\nNK_API nk_bool nk_button_label(struct nk_context*, const char *title);\nNK_API nk_bool nk_button_color(struct nk_context*, struct nk_color);\nNK_API nk_bool nk_button_symbol(struct nk_context*, enum nk_symbol_type);\nNK_API nk_bool nk_button_image(struct nk_context*, struct nk_image img);\nNK_API nk_bool nk_button_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags text_alignment);\nNK_API nk_bool nk_button_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);\nNK_API nk_bool nk_button_image_label(struct nk_context*, struct nk_image img, const char*, nk_flags text_alignment);\nNK_API nk_bool nk_button_image_text(struct nk_context*, struct nk_image img, const char*, int, nk_flags alignment);\nNK_API nk_bool nk_button_text_styled(struct nk_context*, const struct nk_style_button*, const char *title, int len);\nNK_API nk_bool nk_button_label_styled(struct nk_context*, const struct nk_style_button*, const char *title);\nNK_API nk_bool nk_button_symbol_styled(struct nk_context*, const struct nk_style_button*, enum nk_symbol_type);\nNK_API nk_bool nk_button_image_styled(struct nk_context*, const struct nk_style_button*, struct nk_image img);\nNK_API nk_bool nk_button_symbol_text_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, int, nk_flags alignment);\nNK_API nk_bool nk_button_symbol_label_styled(struct nk_context *ctx, const struct nk_style_button *style, enum nk_symbol_type symbol, const char *title, nk_flags align);\nNK_API nk_bool nk_button_image_label_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, nk_flags text_alignment);\nNK_API nk_bool nk_button_image_text_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, int, nk_flags alignment);\nNK_API void nk_button_set_behavior(struct nk_context*, enum nk_button_behavior);\nNK_API nk_bool nk_button_push_behavior(struct nk_context*, enum nk_button_behavior);\nNK_API nk_bool nk_button_pop_behavior(struct nk_context*);\n/* =============================================================================\n *\n *                                  CHECKBOX\n *\n * ============================================================================= */\nNK_API nk_bool nk_check_label(struct nk_context*, const char*, nk_bool active);\nNK_API nk_bool nk_check_text(struct nk_context*, const char*, int, nk_bool active);\nNK_API nk_bool nk_check_text_align(struct nk_context*, const char*, int, nk_bool active, nk_flags widget_alignment, nk_flags text_alignment);\nNK_API unsigned nk_check_flags_label(struct nk_context*, const char*, unsigned int flags, unsigned int value);\nNK_API unsigned nk_check_flags_text(struct nk_context*, const char*, int, unsigned int flags, unsigned int value);\nNK_API nk_bool nk_checkbox_label(struct nk_context*, const char*, nk_bool *active);\nNK_API nk_bool nk_checkbox_label_align(struct nk_context *ctx, const char *label, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment);\nNK_API nk_bool nk_checkbox_text(struct nk_context*, const char*, int, nk_bool *active);\nNK_API nk_bool nk_checkbox_text_align(struct nk_context *ctx, const char *text, int len, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment);\nNK_API nk_bool nk_checkbox_flags_label(struct nk_context*, const char*, unsigned int *flags, unsigned int value);\nNK_API nk_bool nk_checkbox_flags_text(struct nk_context*, const char*, int, unsigned int *flags, unsigned int value);\n/* =============================================================================\n *\n *                                  RADIO BUTTON\n *\n * ============================================================================= */\nNK_API nk_bool nk_radio_label(struct nk_context*, const char*, nk_bool *active);\nNK_API nk_bool nk_radio_label_align(struct nk_context *ctx, const char *label, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment);\nNK_API nk_bool nk_radio_text(struct nk_context*, const char*, int, nk_bool *active);\nNK_API nk_bool nk_radio_text_align(struct nk_context *ctx, const char *text, int len, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment);\nNK_API nk_bool nk_option_label(struct nk_context*, const char*, nk_bool active);\nNK_API nk_bool nk_option_label_align(struct nk_context *ctx, const char *label, nk_bool active, nk_flags widget_alignment, nk_flags text_alignment);\nNK_API nk_bool nk_option_text(struct nk_context*, const char*, int, nk_bool active);\nNK_API nk_bool nk_option_text_align(struct nk_context *ctx, const char *text, int len, nk_bool is_active, nk_flags widget_alignment, nk_flags text_alignment);\n/* =============================================================================\n *\n *                                  SELECTABLE\n *\n * ============================================================================= */\nNK_API nk_bool nk_selectable_label(struct nk_context*, const char*, nk_flags align, nk_bool *value);\nNK_API nk_bool nk_selectable_text(struct nk_context*, const char*, int, nk_flags align, nk_bool *value);\nNK_API nk_bool nk_selectable_image_label(struct nk_context*,struct nk_image,  const char*, nk_flags align, nk_bool *value);\nNK_API nk_bool nk_selectable_image_text(struct nk_context*,struct nk_image, const char*, int, nk_flags align, nk_bool *value);\nNK_API nk_bool nk_selectable_symbol_label(struct nk_context*,enum nk_symbol_type,  const char*, nk_flags align, nk_bool *value);\nNK_API nk_bool nk_selectable_symbol_text(struct nk_context*,enum nk_symbol_type, const char*, int, nk_flags align, nk_bool *value);\n\nNK_API nk_bool nk_select_label(struct nk_context*, const char*, nk_flags align, nk_bool value);\nNK_API nk_bool nk_select_text(struct nk_context*, const char*, int, nk_flags align, nk_bool value);\nNK_API nk_bool nk_select_image_label(struct nk_context*, struct nk_image,const char*, nk_flags align, nk_bool value);\nNK_API nk_bool nk_select_image_text(struct nk_context*, struct nk_image,const char*, int, nk_flags align, nk_bool value);\nNK_API nk_bool nk_select_symbol_label(struct nk_context*,enum nk_symbol_type,  const char*, nk_flags align, nk_bool value);\nNK_API nk_bool nk_select_symbol_text(struct nk_context*,enum nk_symbol_type, const char*, int, nk_flags align, nk_bool value);\n\n/* =============================================================================\n *\n *                                  SLIDER\n *\n * ============================================================================= */\nNK_API float nk_slide_float(struct nk_context*, float min, float val, float max, float step);\nNK_API int nk_slide_int(struct nk_context*, int min, int val, int max, int step);\nNK_API nk_bool nk_slider_float(struct nk_context*, float min, float *val, float max, float step);\nNK_API nk_bool nk_slider_int(struct nk_context*, int min, int *val, int max, int step);\n\n/* =============================================================================\n *\n *                                   KNOB\n *\n * ============================================================================= */\nNK_API nk_bool nk_knob_float(struct nk_context*, float min, float *val, float max, float step, enum nk_heading zero_direction, float dead_zone_degrees);\nNK_API nk_bool nk_knob_int(struct nk_context*, int min, int *val, int max, int step, enum nk_heading zero_direction, float dead_zone_degrees);\n\n/* =============================================================================\n *\n *                                  PROGRESSBAR\n *\n * ============================================================================= */\nNK_API nk_bool nk_progress(struct nk_context*, nk_size *cur, nk_size max, nk_bool modifyable);\nNK_API nk_size nk_prog(struct nk_context*, nk_size cur, nk_size max, nk_bool modifyable);\n\n/* =============================================================================\n *\n *                                  COLOR PICKER\n *\n * ============================================================================= */\nNK_API struct nk_colorf nk_color_picker(struct nk_context*, struct nk_colorf, enum nk_color_format);\nNK_API nk_bool nk_color_pick(struct nk_context*, struct nk_colorf*, enum nk_color_format);\n/* =============================================================================\n *\n *                                  PROPERTIES\n *\n * =============================================================================*/\n/**\n * \\page Properties\n * Properties are the main value modification widgets in Nuklear. Changing a value\n * can be achieved by dragging, adding/removing incremental steps on button click\n * or by directly typing a number.\n *\n * # Usage\n * Each property requires a unique name for identification that is also used for\n * displaying a label. If you want to use the same name multiple times make sure\n * add a '#' before your name. The '#' will not be shown but will generate a\n * unique ID. Each property also takes in a minimum and maximum value. If you want\n * to make use of the complete number range of a type just use the provided\n * type limits from `limits.h`. For example `INT_MIN` and `INT_MAX` for\n * `nk_property_int` and `nk_propertyi`. In additional each property takes in\n * a increment value that will be added or subtracted if either the increment\n * decrement button is clicked. Finally there is a value for increment per pixel\n * dragged that is added or subtracted from the value.\n *\n * ```c\n * int value = 0;\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     // Input\n *     Event evt;\n *     nk_input_begin(&ctx);\n *     while (GetEvent(&evt)) {\n *         if (evt.type == MOUSE_MOVE)\n *             nk_input_motion(&ctx, evt.motion.x, evt.motion.y);\n *         else if (evt.type == [...]) {\n *             nk_input_xxx(...);\n *         }\n *     }\n *     nk_input_end(&ctx);\n *     //\n *     // Window\n *     if (nk_begin_xxx(...) {\n *         // Property\n *         nk_layout_row_dynamic(...);\n *         nk_property_int(ctx, \"ID\", INT_MIN, &value, INT_MAX, 1, 1);\n *     }\n *     nk_end(ctx);\n *     //\n *     // Draw\n *     const struct nk_command *cmd = 0;\n *     nk_foreach(cmd, &ctx) {\n *     switch (cmd->type) {\n *     case NK_COMMAND_LINE:\n *         your_draw_line_function(...)\n *         break;\n *     case NK_COMMAND_RECT\n *         your_draw_rect_function(...)\n *         break;\n *     case ...:\n *         // [...]\n *     }\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n *\n * # Reference\n * Function            | Description\n * --------------------|-------------------------------------------\n * \\ref nk_property_int     | Integer property directly modifying a passed in value\n * \\ref nk_property_float   | Float property directly modifying a passed in value\n * \\ref nk_property_double  | Double property directly modifying a passed in value\n * \\ref nk_propertyi        | Integer property returning the modified int value\n * \\ref nk_propertyf        | Float property returning the modified float value\n * \\ref nk_propertyd        | Double property returning the modified double value\n *\n\n * # # nk_property_int\n * Integer property directly modifying a passed in value\n * !!! \\warning\n *     To generate a unique property ID using the same label make sure to insert\n *     a `#` at the beginning. It will not be shown but guarantees correct behavior.\n *\n * ```c\n * nk_bool nk_property_int(struct nk_context *ctx, const char *name, int min, int *val, int max, int step, float inc_per_pixel);\n * ```\n *\n * Parameter           | Description\n * --------------------|-----------------------------------------------------------\n * \\param[in] ctx             | Must point to an previously initialized `nk_context` struct after calling a layouting function\n * \\param[in] name            | String used both as a label as well as a unique identifier\n * \\param[in] min             | Minimum value not allowed to be underflown\n * \\param[in] val             | Integer pointer to be modified\n * \\param[in] max             | Maximum value not allowed to be overflown\n * \\param[in] step            | Increment added and subtracted on increment and decrement button\n * \\param[in] inc_per_pixel   | Value per pixel added or subtracted on dragging\n *\n * \\returns `true(1)` if the value changed\n */\nNK_API nk_bool nk_property_int(struct nk_context*, const char *name, int min, int *val, int max, int step, float inc_per_pixel);\n\n/**\n * # # nk_property_float\n * Float property directly modifying a passed in value\n * !!! \\warning\n *     To generate a unique property ID using the same label make sure to insert\n *     a `#` at the beginning. It will not be shown but guarantees correct behavior.\n *\n * ```c\n * nk_bool nk_property_float(struct nk_context *ctx, const char *name, float min, float *val, float max, float step, float inc_per_pixel);\n * ```\n *\n * Parameter           | Description\n * --------------------|-----------------------------------------------------------\n * \\param[in] ctx             | Must point to an previously initialized `nk_context` struct after calling a layouting function\n * \\param[in] name            | String used both as a label as well as a unique identifier\n * \\param[in] min             | Minimum value not allowed to be underflown\n * \\param[in] val             | Float pointer to be modified\n * \\param[in] max             | Maximum value not allowed to be overflown\n * \\param[in] step            | Increment added and subtracted on increment and decrement button\n * \\param[in] inc_per_pixel   | Value per pixel added or subtracted on dragging\n *\n * \\returns `true(1)` if the value changed\n */\nNK_API nk_bool nk_property_float(struct nk_context*, const char *name, float min, float *val, float max, float step, float inc_per_pixel);\n\n/**\n * # # nk_property_double\n * Double property directly modifying a passed in value\n * !!! \\warning\n *     To generate a unique property ID using the same label make sure to insert\n *     a `#` at the beginning. It will not be shown but guarantees correct behavior.\n *\n * ```c\n * nk_bool nk_property_double(struct nk_context *ctx, const char *name, double min, double *val, double max, double step, double inc_per_pixel);\n * ```\n *\n * Parameter           | Description\n * --------------------|-----------------------------------------------------------\n * \\param[in] ctx             | Must point to an previously initialized `nk_context` struct after calling a layouting function\n * \\param[in] name            | String used both as a label as well as a unique identifier\n * \\param[in] min             | Minimum value not allowed to be underflown\n * \\param[in] val             | Double pointer to be modified\n * \\param[in] max             | Maximum value not allowed to be overflown\n * \\param[in] step            | Increment added and subtracted on increment and decrement button\n * \\param[in] inc_per_pixel   | Value per pixel added or subtracted on dragging\n *\n * \\returns `true(1)` if the value changed\n */\nNK_API nk_bool nk_property_double(struct nk_context*, const char *name, double min, double *val, double max, double step, float inc_per_pixel);\n\n/**\n * # # nk_propertyi\n * Integer property modifying a passed in value and returning the new value\n * !!! \\warning\n *     To generate a unique property ID using the same label make sure to insert\n *     a `#` at the beginning. It will not be shown but guarantees correct behavior.\n *\n * ```c\n * int nk_propertyi(struct nk_context *ctx, const char *name, int min, int val, int max, int step, float inc_per_pixel);\n * ```\n *\n * \\param[in] ctx              Must point to an previously initialized `nk_context` struct after calling a layouting function\n * \\param[in] name             String used both as a label as well as a unique identifier\n * \\param[in] min              Minimum value not allowed to be underflown\n * \\param[in] val              Current integer value to be modified and returned\n * \\param[in] max              Maximum value not allowed to be overflown\n * \\param[in] step             Increment added and subtracted on increment and decrement button\n * \\param[in] inc_per_pixel    Value per pixel added or subtracted on dragging\n *\n * \\returns the new modified integer value\n */\nNK_API int nk_propertyi(struct nk_context*, const char *name, int min, int val, int max, int step, float inc_per_pixel);\n\n/**\n * # # nk_propertyf\n * Float property modifying a passed in value and returning the new value\n * !!! \\warning\n *     To generate a unique property ID using the same label make sure to insert\n *     a `#` at the beginning. It will not be shown but guarantees correct behavior.\n *\n * ```c\n * float nk_propertyf(struct nk_context *ctx, const char *name, float min, float val, float max, float step, float inc_per_pixel);\n * ```\n *\n * \\param[in] ctx              Must point to an previously initialized `nk_context` struct after calling a layouting function\n * \\param[in] name             String used both as a label as well as a unique identifier\n * \\param[in] min              Minimum value not allowed to be underflown\n * \\param[in] val              Current float value to be modified and returned\n * \\param[in] max              Maximum value not allowed to be overflown\n * \\param[in] step             Increment added and subtracted on increment and decrement button\n * \\param[in] inc_per_pixel    Value per pixel added or subtracted on dragging\n *\n * \\returns the new modified float value\n */\nNK_API float nk_propertyf(struct nk_context*, const char *name, float min, float val, float max, float step, float inc_per_pixel);\n\n/**\n * # # nk_propertyd\n * Float property modifying a passed in value and returning the new value\n * !!! \\warning\n *     To generate a unique property ID using the same label make sure to insert\n *     a `#` at the beginning. It will not be shown but guarantees correct behavior.\n *\n * ```c\n * float nk_propertyd(struct nk_context *ctx, const char *name, double min, double val, double max, double step, double inc_per_pixel);\n * ```\n *\n * \\param[in] ctx              Must point to an previously initialized `nk_context` struct after calling a layouting function\n * \\param[in] name             String used both as a label as well as a unique identifier\n * \\param[in] min              Minimum value not allowed to be underflown\n * \\param[in] val              Current double value to be modified and returned\n * \\param[in] max              Maximum value not allowed to be overflown\n * \\param[in] step             Increment added and subtracted on increment and decrement button\n * \\param[in] inc_per_pixel    Value per pixel added or subtracted on dragging\n *\n * \\returns the new modified double value\n */\nNK_API double nk_propertyd(struct nk_context*, const char *name, double min, double val, double max, double step, float inc_per_pixel);\n\n/* =============================================================================\n *\n *                                  TEXT EDIT\n *\n * ============================================================================= */\nenum nk_edit_flags {\n    NK_EDIT_DEFAULT                 = 0,\n    NK_EDIT_READ_ONLY               = NK_FLAG(0),\n    NK_EDIT_AUTO_SELECT             = NK_FLAG(1),\n    NK_EDIT_SIG_ENTER               = NK_FLAG(2),\n    NK_EDIT_ALLOW_TAB               = NK_FLAG(3),\n    NK_EDIT_NO_CURSOR               = NK_FLAG(4),\n    NK_EDIT_SELECTABLE              = NK_FLAG(5),\n    NK_EDIT_CLIPBOARD               = NK_FLAG(6),\n    NK_EDIT_CTRL_ENTER_NEWLINE      = NK_FLAG(7),\n    NK_EDIT_NO_HORIZONTAL_SCROLL    = NK_FLAG(8),\n    NK_EDIT_ALWAYS_INSERT_MODE      = NK_FLAG(9),\n    NK_EDIT_MULTILINE               = NK_FLAG(10),\n    NK_EDIT_GOTO_END_ON_ACTIVATE    = NK_FLAG(11)\n};\nenum nk_edit_types {\n    NK_EDIT_SIMPLE  = NK_EDIT_ALWAYS_INSERT_MODE,\n    NK_EDIT_FIELD   = NK_EDIT_SIMPLE|NK_EDIT_SELECTABLE|NK_EDIT_CLIPBOARD,\n    NK_EDIT_BOX     = NK_EDIT_ALWAYS_INSERT_MODE| NK_EDIT_SELECTABLE| NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB|NK_EDIT_CLIPBOARD,\n    NK_EDIT_EDITOR  = NK_EDIT_SELECTABLE|NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB| NK_EDIT_CLIPBOARD\n};\nenum nk_edit_events {\n    NK_EDIT_ACTIVE      = NK_FLAG(0), /**!< edit widget is currently being modified */\n    NK_EDIT_INACTIVE    = NK_FLAG(1), /**!< edit widget is not active and is not being modified */\n    NK_EDIT_ACTIVATED   = NK_FLAG(2), /**!< edit widget went from state inactive to state active */\n    NK_EDIT_DEACTIVATED = NK_FLAG(3), /**!< edit widget went from state active to state inactive */\n    NK_EDIT_COMMITED    = NK_FLAG(4)  /**!< edit widget has received an enter and lost focus */\n};\nNK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter);\nNK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter);\nNK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter);\nNK_API void nk_edit_focus(struct nk_context*, nk_flags flags);\nNK_API void nk_edit_unfocus(struct nk_context*);\n/* =============================================================================\n *\n *                                  CHART\n *\n * ============================================================================= */\nNK_API nk_bool nk_chart_begin(struct nk_context*, enum nk_chart_type, int num, float min, float max);\nNK_API nk_bool nk_chart_begin_colored(struct nk_context*, enum nk_chart_type, struct nk_color, struct nk_color active, int num, float min, float max);\nNK_API void nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type, int count, float min_value, float max_value);\nNK_API void nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type, struct nk_color, struct nk_color active, int count, float min_value, float max_value);\nNK_API nk_flags nk_chart_push(struct nk_context*, float);\nNK_API nk_flags nk_chart_push_slot(struct nk_context*, float, int);\nNK_API void nk_chart_end(struct nk_context*);\nNK_API void nk_plot(struct nk_context*, enum nk_chart_type, const float *values, int count, int offset);\nNK_API void nk_plot_function(struct nk_context*, enum nk_chart_type, void *userdata, float(*value_getter)(void* user, int index), int count, int offset);\n/* =============================================================================\n *\n *                                  POPUP\n *\n * ============================================================================= */\nNK_API nk_bool nk_popup_begin(struct nk_context*, enum nk_popup_type, const char*, nk_flags, struct nk_rect bounds);\nNK_API void nk_popup_close(struct nk_context*);\nNK_API void nk_popup_end(struct nk_context*);\nNK_API void nk_popup_get_scroll(const struct nk_context*, nk_uint *offset_x, nk_uint *offset_y);\nNK_API void nk_popup_set_scroll(struct nk_context*, nk_uint offset_x, nk_uint offset_y);\n/* =============================================================================\n *\n *                                  COMBOBOX\n *\n * ============================================================================= */\nNK_API int nk_combo(struct nk_context*, const char *const *items, int count, int selected, int item_height, struct nk_vec2 size);\nNK_API int nk_combo_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int selected, int count, int item_height, struct nk_vec2 size);\nNK_API int nk_combo_string(struct nk_context*, const char *items_separated_by_zeros, int selected, int count, int item_height, struct nk_vec2 size);\nNK_API int nk_combo_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void *userdata, int selected, int count, int item_height, struct nk_vec2 size);\nNK_API nk_bool nk_combobox(struct nk_context*, const char *const *items, int count, int *selected, int item_height, struct nk_vec2 size);\nNK_API nk_bool nk_combobox_string(struct nk_context*, const char *items_separated_by_zeros, int *selected, int count, int item_height, struct nk_vec2 size);\nNK_API nk_bool nk_combobox_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int *selected, int count, int item_height, struct nk_vec2 size);\nNK_API nk_bool nk_combobox_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void*, int *selected, int count, int item_height, struct nk_vec2 size);\n/* =============================================================================\n *\n *                                  ABSTRACT COMBOBOX\n *\n * ============================================================================= */\nNK_API nk_bool nk_combo_begin_text(struct nk_context*, const char *selected, int, struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_label(struct nk_context*, const char *selected, struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_color(struct nk_context*, struct nk_color color, struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_symbol(struct nk_context*,  enum nk_symbol_type,  struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_symbol_label(struct nk_context*, const char *selected, enum nk_symbol_type, struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_symbol_text(struct nk_context*, const char *selected, int, enum nk_symbol_type, struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_image(struct nk_context*, struct nk_image img,  struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_image_label(struct nk_context*, const char *selected, struct nk_image, struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_image_text(struct nk_context*,  const char *selected, int, struct nk_image, struct nk_vec2 size);\nNK_API nk_bool nk_combo_item_label(struct nk_context*, const char*, nk_flags alignment);\nNK_API nk_bool nk_combo_item_text(struct nk_context*, const char*,int, nk_flags alignment);\nNK_API nk_bool nk_combo_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);\nNK_API nk_bool nk_combo_item_image_text(struct nk_context*, struct nk_image, const char*, int,nk_flags alignment);\nNK_API nk_bool nk_combo_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);\nNK_API nk_bool nk_combo_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);\nNK_API void nk_combo_close(struct nk_context*);\nNK_API void nk_combo_end(struct nk_context*);\n/* =============================================================================\n *\n *                                  CONTEXTUAL\n *\n * ============================================================================= */\nNK_API nk_bool nk_contextual_begin(struct nk_context*, nk_flags, struct nk_vec2, struct nk_rect trigger_bounds);\nNK_API nk_bool nk_contextual_item_text(struct nk_context*, const char*, int,nk_flags align);\nNK_API nk_bool nk_contextual_item_label(struct nk_context*, const char*, nk_flags align);\nNK_API nk_bool nk_contextual_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);\nNK_API nk_bool nk_contextual_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment);\nNK_API nk_bool nk_contextual_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);\nNK_API nk_bool nk_contextual_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);\nNK_API void nk_contextual_close(struct nk_context*);\nNK_API void nk_contextual_end(struct nk_context*);\n/* =============================================================================\n *\n *                                  TOOLTIP\n *\n * ============================================================================= */\nNK_API void nk_tooltip(struct nk_context*, const char*);\nNK_API void nk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset);\n#ifdef NK_INCLUDE_STANDARD_VARARGS\nNK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2);\nNK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2);\nNK_API void nk_tooltipf_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(4);\nNK_API void nk_tooltipfv_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(4);\n#endif\nNK_API nk_bool nk_tooltip_begin(struct nk_context*, float width);\nNK_API nk_bool nk_tooltip_begin_offset(struct nk_context*, float, enum nk_tooltip_pos, struct nk_vec2);\nNK_API void nk_tooltip_end(struct nk_context*);\n/* =============================================================================\n *\n *                                  MENU\n *\n * ============================================================================= */\nNK_API void nk_menubar_begin(struct nk_context*);\nNK_API void nk_menubar_end(struct nk_context*);\nNK_API nk_bool nk_menu_begin_text(struct nk_context*, const char* title, int title_len, nk_flags align, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_label(struct nk_context*, const char*, nk_flags align, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_image(struct nk_context*, const char*, struct nk_image, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_image_text(struct nk_context*, const char*, int,nk_flags align,struct nk_image, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_image_label(struct nk_context*, const char*, nk_flags align,struct nk_image, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_symbol(struct nk_context*, const char*, enum nk_symbol_type, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_symbol_text(struct nk_context*, const char*, int,nk_flags align,enum nk_symbol_type, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_symbol_label(struct nk_context*, const char*, nk_flags align,enum nk_symbol_type, struct nk_vec2 size);\nNK_API nk_bool nk_menu_item_text(struct nk_context*, const char*, int,nk_flags align);\nNK_API nk_bool nk_menu_item_label(struct nk_context*, const char*, nk_flags alignment);\nNK_API nk_bool nk_menu_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);\nNK_API nk_bool nk_menu_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment);\nNK_API nk_bool nk_menu_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);\nNK_API nk_bool nk_menu_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);\nNK_API void nk_menu_close(struct nk_context*);\nNK_API void nk_menu_end(struct nk_context*);\n/* =============================================================================\n *\n *                                  STYLE\n *\n * ============================================================================= */\n\n#define NK_WIDGET_DISABLED_FACTOR 0.5f\n\nenum nk_style_colors {\n    NK_COLOR_TEXT,\n    NK_COLOR_WINDOW,\n    NK_COLOR_HEADER,\n    NK_COLOR_BORDER,\n    NK_COLOR_BUTTON,\n    NK_COLOR_BUTTON_HOVER,\n    NK_COLOR_BUTTON_ACTIVE,\n    NK_COLOR_TOGGLE,\n    NK_COLOR_TOGGLE_HOVER,\n    NK_COLOR_TOGGLE_CURSOR,\n    NK_COLOR_SELECT,\n    NK_COLOR_SELECT_ACTIVE,\n    NK_COLOR_SLIDER,\n    NK_COLOR_SLIDER_CURSOR,\n    NK_COLOR_SLIDER_CURSOR_HOVER,\n    NK_COLOR_SLIDER_CURSOR_ACTIVE,\n    NK_COLOR_PROPERTY,\n    NK_COLOR_EDIT,\n    NK_COLOR_EDIT_CURSOR,\n    NK_COLOR_COMBO,\n    NK_COLOR_CHART,\n    NK_COLOR_CHART_COLOR,\n    NK_COLOR_CHART_COLOR_HIGHLIGHT,\n    NK_COLOR_SCROLLBAR,\n    NK_COLOR_SCROLLBAR_CURSOR,\n    NK_COLOR_SCROLLBAR_CURSOR_HOVER,\n    NK_COLOR_SCROLLBAR_CURSOR_ACTIVE,\n    NK_COLOR_TAB_HEADER,\n    NK_COLOR_KNOB,\n    NK_COLOR_KNOB_CURSOR,\n    NK_COLOR_KNOB_CURSOR_HOVER,\n    NK_COLOR_KNOB_CURSOR_ACTIVE,\n    NK_COLOR_COUNT\n};\nenum nk_style_cursor {\n    NK_CURSOR_ARROW,\n    NK_CURSOR_TEXT,\n    NK_CURSOR_MOVE,\n    NK_CURSOR_RESIZE_VERTICAL,\n    NK_CURSOR_RESIZE_HORIZONTAL,\n    NK_CURSOR_RESIZE_TOP_LEFT_DOWN_RIGHT,\n    NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT,\n    NK_CURSOR_COUNT\n};\nNK_API void nk_style_default(struct nk_context*);\nNK_API void nk_style_from_table(struct nk_context*, const struct nk_color*);\nNK_API void nk_style_load_cursor(struct nk_context*, enum nk_style_cursor, const struct nk_cursor*);\nNK_API void nk_style_load_all_cursors(struct nk_context*, const struct nk_cursor*);\nNK_API const char* nk_style_get_color_by_name(enum nk_style_colors);\nNK_API void nk_style_set_font(struct nk_context*, const struct nk_user_font*);\nNK_API nk_bool nk_style_set_cursor(struct nk_context*, enum nk_style_cursor);\nNK_API void nk_style_show_cursor(struct nk_context*);\nNK_API void nk_style_hide_cursor(struct nk_context*);\n\nNK_API nk_bool nk_style_push_font(struct nk_context*, const struct nk_user_font*);\nNK_API nk_bool nk_style_push_float(struct nk_context*, float*, float);\nNK_API nk_bool nk_style_push_vec2(struct nk_context*, struct nk_vec2*, struct nk_vec2);\nNK_API nk_bool nk_style_push_style_item(struct nk_context*, struct nk_style_item*, struct nk_style_item);\nNK_API nk_bool nk_style_push_flags(struct nk_context*, nk_flags*, nk_flags);\nNK_API nk_bool nk_style_push_color(struct nk_context*, struct nk_color*, struct nk_color);\n\nNK_API nk_bool nk_style_pop_font(struct nk_context*);\nNK_API nk_bool nk_style_pop_float(struct nk_context*);\nNK_API nk_bool nk_style_pop_vec2(struct nk_context*);\nNK_API nk_bool nk_style_pop_style_item(struct nk_context*);\nNK_API nk_bool nk_style_pop_flags(struct nk_context*);\nNK_API nk_bool nk_style_pop_color(struct nk_context*);\n/* =============================================================================\n *\n *                                  COLOR\n *\n * ============================================================================= */\nNK_API struct nk_color nk_rgb(int r, int g, int b);\nNK_API struct nk_color nk_rgb_iv(const int *rgb);\nNK_API struct nk_color nk_rgb_bv(const nk_byte* rgb);\nNK_API struct nk_color nk_rgb_f(float r, float g, float b);\nNK_API struct nk_color nk_rgb_fv(const float *rgb);\nNK_API struct nk_color nk_rgb_cf(struct nk_colorf c);\nNK_API struct nk_color nk_rgb_hex(const char *rgb);\nNK_API struct nk_color nk_rgb_factor(struct nk_color col, float factor);\n\nNK_API struct nk_color nk_rgba(int r, int g, int b, int a);\nNK_API struct nk_color nk_rgba_u32(nk_uint);\nNK_API struct nk_color nk_rgba_iv(const int *rgba);\nNK_API struct nk_color nk_rgba_bv(const nk_byte *rgba);\nNK_API struct nk_color nk_rgba_f(float r, float g, float b, float a);\nNK_API struct nk_color nk_rgba_fv(const float *rgba);\nNK_API struct nk_color nk_rgba_cf(struct nk_colorf c);\nNK_API struct nk_color nk_rgba_hex(const char *rgb);\n\nNK_API struct nk_colorf nk_hsva_colorf(float h, float s, float v, float a);\nNK_API struct nk_colorf nk_hsva_colorfv(const float *c);\nNK_API void nk_colorf_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_colorf in);\nNK_API void nk_colorf_hsva_fv(float *hsva, struct nk_colorf in);\n\nNK_API struct nk_color nk_hsv(int h, int s, int v);\nNK_API struct nk_color nk_hsv_iv(const int *hsv);\nNK_API struct nk_color nk_hsv_bv(const nk_byte *hsv);\nNK_API struct nk_color nk_hsv_f(float h, float s, float v);\nNK_API struct nk_color nk_hsv_fv(const float *hsv);\n\nNK_API struct nk_color nk_hsva(int h, int s, int v, int a);\nNK_API struct nk_color nk_hsva_iv(const int *hsva);\nNK_API struct nk_color nk_hsva_bv(const nk_byte *hsva);\nNK_API struct nk_color nk_hsva_f(float h, float s, float v, float a);\nNK_API struct nk_color nk_hsva_fv(const float *hsva);\n\n/* color (conversion nuklear --> user) */\nNK_API void nk_color_f(float *r, float *g, float *b, float *a, struct nk_color);\nNK_API void nk_color_fv(float *rgba_out, struct nk_color);\nNK_API struct nk_colorf nk_color_cf(struct nk_color);\nNK_API void nk_color_d(double *r, double *g, double *b, double *a, struct nk_color);\nNK_API void nk_color_dv(double *rgba_out, struct nk_color);\n\nNK_API nk_uint nk_color_u32(struct nk_color);\nNK_API void nk_color_hex_rgba(char *output, struct nk_color);\nNK_API void nk_color_hex_rgb(char *output, struct nk_color);\n\nNK_API void nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color);\nNK_API void nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color);\nNK_API void nk_color_hsv_iv(int *hsv_out, struct nk_color);\nNK_API void nk_color_hsv_bv(nk_byte *hsv_out, struct nk_color);\nNK_API void nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color);\nNK_API void nk_color_hsv_fv(float *hsv_out, struct nk_color);\n\nNK_API void nk_color_hsva_i(int *h, int *s, int *v, int *a, struct nk_color);\nNK_API void nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color);\nNK_API void nk_color_hsva_iv(int *hsva_out, struct nk_color);\nNK_API void nk_color_hsva_bv(nk_byte *hsva_out, struct nk_color);\nNK_API void nk_color_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_color);\nNK_API void nk_color_hsva_fv(float *hsva_out, struct nk_color);\n/* =============================================================================\n *\n *                                  IMAGE\n *\n * ============================================================================= */\nNK_API nk_handle nk_handle_ptr(void*);\nNK_API nk_handle nk_handle_id(int);\nNK_API struct nk_image nk_image_handle(nk_handle);\nNK_API struct nk_image nk_image_ptr(void*);\nNK_API struct nk_image nk_image_id(int);\nNK_API nk_bool nk_image_is_subimage(const struct nk_image* img);\nNK_API struct nk_image nk_subimage_ptr(void*, nk_ushort w, nk_ushort h, struct nk_rect sub_region);\nNK_API struct nk_image nk_subimage_id(int, nk_ushort w, nk_ushort h, struct nk_rect sub_region);\nNK_API struct nk_image nk_subimage_handle(nk_handle, nk_ushort w, nk_ushort h, struct nk_rect sub_region);\n/* =============================================================================\n *\n *                                  9-SLICE\n *\n * ============================================================================= */\nNK_API struct nk_nine_slice nk_nine_slice_handle(nk_handle, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);\nNK_API struct nk_nine_slice nk_nine_slice_ptr(void*, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);\nNK_API struct nk_nine_slice nk_nine_slice_id(int, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);\nNK_API int nk_nine_slice_is_sub9slice(const struct nk_nine_slice* img);\nNK_API struct nk_nine_slice nk_sub9slice_ptr(void*, nk_ushort w, nk_ushort h, struct nk_rect sub_region, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);\nNK_API struct nk_nine_slice nk_sub9slice_id(int, nk_ushort w, nk_ushort h, struct nk_rect sub_region, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);\nNK_API struct nk_nine_slice nk_sub9slice_handle(nk_handle, nk_ushort w, nk_ushort h, struct nk_rect sub_region, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);\n/* =============================================================================\n *\n *                                  MATH\n *\n * ============================================================================= */\nNK_API nk_hash nk_murmur_hash(const void *key, int len, nk_hash seed);\nNK_API void nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, float pad_x, float pad_y, enum nk_heading);\n\nNK_API struct nk_vec2 nk_vec2(float x, float y);\nNK_API struct nk_vec2 nk_vec2i(int x, int y);\nNK_API struct nk_vec2 nk_vec2v(const float *xy);\nNK_API struct nk_vec2 nk_vec2iv(const int *xy);\n\nNK_API struct nk_rect nk_get_null_rect(void);\nNK_API struct nk_rect nk_rect(float x, float y, float w, float h);\nNK_API struct nk_rect nk_recti(int x, int y, int w, int h);\nNK_API struct nk_rect nk_recta(struct nk_vec2 pos, struct nk_vec2 size);\nNK_API struct nk_rect nk_rectv(const float *xywh);\nNK_API struct nk_rect nk_rectiv(const int *xywh);\nNK_API struct nk_vec2 nk_rect_pos(struct nk_rect);\nNK_API struct nk_vec2 nk_rect_size(struct nk_rect);\n/* =============================================================================\n *\n *                                  STRING\n *\n * ============================================================================= */\nNK_API int nk_strlen(const char *str);\nNK_API int nk_stricmp(const char *s1, const char *s2);\nNK_API int nk_stricmpn(const char *s1, const char *s2, int n);\nNK_API int nk_strtoi(const char *str, char **endptr);\nNK_API float nk_strtof(const char *str, char **endptr);\n#ifndef NK_STRTOD\n#define NK_STRTOD nk_strtod\n#define NK_STRTOD_NEEDED\nNK_API double nk_strtod(const char *str, char **endptr);\n#endif\nNK_API int nk_strfilter(const char *text, const char *regexp);\nNK_API int nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score);\nNK_API int nk_strmatch_fuzzy_text(const char *txt, int txt_len, const char *pattern, int *out_score);\n/* =============================================================================\n *\n *                                  UTF-8\n *\n * ============================================================================= */\nNK_API int nk_utf_decode(const char*, nk_rune*, int);\nNK_API int nk_utf_encode(nk_rune, char*, int);\nNK_API int nk_utf_len(const char*, int byte_len);\nNK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune *unicode, int *len);\n/* ===============================================================\n *\n *                          FONT\n *\n * ===============================================================*/\n/**\n * \\page Font\n * Font handling in this library was designed to be quite customizable and lets\n * you decide what you want to use and what you want to provide. There are three\n * different ways to use the font atlas. The first two will use your font\n * handling scheme and only requires essential data to run nuklear. The next\n * slightly more advanced features is font handling with vertex buffer output.\n * Finally the most complex API wise is using nuklear's font baking API.\n *\n * # Using your own implementation without vertex buffer output\n *\n * So first up the easiest way to do font handling is by just providing a\n * `nk_user_font` struct which only requires the height in pixel of the used\n * font and a callback to calculate the width of a string. This way of handling\n * fonts is best fitted for using the normal draw shape command API where you\n * do all the text drawing yourself and the library does not require any kind\n * of deeper knowledge about which font handling mechanism you use.\n * IMPORTANT: the `nk_user_font` pointer provided to nuklear has to persist\n * over the complete life time! I know this sucks but it is currently the only\n * way to switch between fonts.\n *\n * ```c\n *     float your_text_width_calculation(nk_handle handle, float height, const char *text, int len)\n *     {\n *         your_font_type *type = handle.ptr;\n *         float text_width = ...;\n *         return text_width;\n *     }\n *\n *     struct nk_user_font font;\n *     font.userdata.ptr = &your_font_class_or_struct;\n *     font.height = your_font_height;\n *     font.width = your_text_width_calculation;\n *\n *     struct nk_context ctx;\n *     nk_init_default(&ctx, &font);\n * ```\n * # Using your own implementation with vertex buffer output\n *\n * While the first approach works fine if you don't want to use the optional\n * vertex buffer output it is not enough if you do. To get font handling working\n * for these cases you have to provide two additional parameters inside the\n * `nk_user_font`. First a texture atlas handle used to draw text as subimages\n * of a bigger font atlas texture and a callback to query a character's glyph\n * information (offset, size, ...). So it is still possible to provide your own\n * font and use the vertex buffer output.\n *\n * ```c\n *     float your_text_width_calculation(nk_handle handle, float height, const char *text, int len)\n *     {\n *         your_font_type *type = handle.ptr;\n *         float text_width = ...;\n *         return text_width;\n *     }\n *     void query_your_font_glyph(nk_handle handle, float font_height, struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint)\n *     {\n *         your_font_type *type = handle.ptr;\n *         glyph.width = ...;\n *         glyph.height = ...;\n *         glyph.xadvance = ...;\n *         glyph.uv[0].x = ...;\n *         glyph.uv[0].y = ...;\n *         glyph.uv[1].x = ...;\n *         glyph.uv[1].y = ...;\n *         glyph.offset.x = ...;\n *         glyph.offset.y = ...;\n *     }\n *\n *     struct nk_user_font font;\n *     font.userdata.ptr = &your_font_class_or_struct;\n *     font.height = your_font_height;\n *     font.width = your_text_width_calculation;\n *     font.query = query_your_font_glyph;\n *     font.texture.id = your_font_texture;\n *\n *     struct nk_context ctx;\n *     nk_init_default(&ctx, &font);\n * ```\n *\n * # Nuklear font baker\n *\n * The final approach if you do not have a font handling functionality or don't\n * want to use it in this library is by using the optional font baker.\n * The font baker APIs can be used to create a font plus font atlas texture\n * and can be used with or without the vertex buffer output.\n *\n * It still uses the `nk_user_font` struct and the two different approaches\n * previously stated still work. The font baker is not located inside\n * `nk_context` like all other systems since it can be understood as more of\n * an extension to nuklear and does not really depend on any `nk_context` state.\n *\n * Font baker need to be initialized first by one of the nk_font_atlas_init_xxx\n * functions. If you don't care about memory just call the default version\n * `nk_font_atlas_init_default` which will allocate all memory from the standard library.\n * If you want to control memory allocation but you don't care if the allocated\n * memory is temporary and therefore can be freed directly after the baking process\n * is over or permanent you can call `nk_font_atlas_init`.\n *\n * After successfully initializing the font baker you can add Truetype(.ttf) fonts from\n * different sources like memory or from file by calling one of the `nk_font_atlas_add_xxx`.\n * functions. Adding font will permanently store each font, font config and ttf memory block(!)\n * inside the font atlas and allows to reuse the font atlas. If you don't want to reuse\n * the font baker by for example adding additional fonts you can call\n * `nk_font_atlas_cleanup` after the baking process is over (after calling nk_font_atlas_end).\n *\n * As soon as you added all fonts you wanted you can now start the baking process\n * for every selected glyph to image by calling `nk_font_atlas_bake`.\n * The baking process returns image memory, width and height which can be used to\n * either create your own image object or upload it to any graphics library.\n * No matter which case you finally have to call `nk_font_atlas_end` which\n * will free all temporary memory including the font atlas image so make sure\n * you created our texture beforehand. `nk_font_atlas_end` requires a handle\n * to your font texture or object and optionally fills a `struct nk_draw_null_texture`\n * which can be used for the optional vertex output. If you don't want it just\n * set the argument to `NULL`.\n *\n * At this point you are done and if you don't want to reuse the font atlas you\n * can call `nk_font_atlas_cleanup` to free all truetype blobs and configuration\n * memory. Finally if you don't use the font atlas and any of it's fonts anymore\n * you need to call `nk_font_atlas_clear` to free all memory still being used.\n *\n * ```c\n *     struct nk_font_atlas atlas;\n *     nk_font_atlas_init_default(&atlas);\n *     nk_font_atlas_begin(&atlas);\n *     nk_font *font = nk_font_atlas_add_from_file(&atlas, \"Path/To/Your/TTF_Font.ttf\", 13, 0);\n *     nk_font *font2 = nk_font_atlas_add_from_file(&atlas, \"Path/To/Your/TTF_Font2.ttf\", 16, 0);\n *     const void* img = nk_font_atlas_bake(&atlas, &img_width, &img_height, NK_FONT_ATLAS_RGBA32);\n *     nk_font_atlas_end(&atlas, nk_handle_id(texture), 0);\n *\n *     struct nk_context ctx;\n *     nk_init_default(&ctx, &font->handle);\n *     while (1) {\n *\n *     }\n *     nk_font_atlas_clear(&atlas);\n * ```\n * The font baker API is probably the most complex API inside this library and\n * I would suggest reading some of my examples `example/` to get a grip on how\n * to use the font atlas. There are a number of details I left out. For example\n * how to merge fonts, configure a font with `nk_font_config` to use other languages,\n * use another texture coordinate format and a lot more:\n *\n * ```c\n *     struct nk_font_config cfg = nk_font_config(font_pixel_height);\n *     cfg.merge_mode = nk_false or nk_true;\n *     cfg.range = nk_font_korean_glyph_ranges();\n *     cfg.coord_type = NK_COORD_PIXEL;\n *     nk_font *font = nk_font_atlas_add_from_file(&atlas, \"Path/To/Your/TTF_Font.ttf\", 13, &cfg);\n * ```\n */\n\nstruct nk_user_font_glyph;\ntypedef float(*nk_text_width_f)(nk_handle, float h, const char*, int len);\ntypedef void(*nk_query_font_glyph_f)(nk_handle handle, float font_height,\n                                    struct nk_user_font_glyph *glyph,\n                                    nk_rune codepoint, nk_rune next_codepoint);\n\n#if defined(NK_INCLUDE_VERTEX_BUFFER_OUTPUT) || defined(NK_INCLUDE_SOFTWARE_FONT)\nstruct nk_user_font_glyph {\n    struct nk_vec2 uv[2];  /**!< texture coordinates */\n    struct nk_vec2 offset; /**!< offset between top left and glyph */\n    float width, height;   /**!< size of the glyph  */\n    float xadvance;        /**!< offset to the next glyph */\n};\n#endif\n\nstruct nk_user_font {\n    nk_handle userdata;    /**!< user provided font handle */\n    float height;          /**!< max height of the font */\n    nk_text_width_f width; /**!< font string width in pixel callback */\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n    nk_query_font_glyph_f query; /**!< font glyph callback to query drawing info */\n    nk_handle texture;           /**!< texture handle to the used font atlas or texture */\n#endif\n};\n\n#ifdef NK_INCLUDE_FONT_BAKING\nenum nk_font_coord_type {\n    NK_COORD_UV,   /**!< texture coordinates inside font glyphs are clamped between 0-1 */\n    NK_COORD_PIXEL /**!< texture coordinates inside font glyphs are in absolute pixel */\n};\n\nstruct nk_font;\nstruct nk_baked_font {\n    float height;          /**!< height of the font  */\n    float ascent;          /**!< font glyphs ascent and descent  */\n    float descent;         /**!< font glyphs ascent and descent  */\n    nk_rune glyph_offset;  /**!< glyph array offset inside the font glyph baking output array  */\n    nk_rune glyph_count;   /**!< number of glyphs of this font inside the glyph baking array output */\n    const nk_rune *ranges; /**!< font codepoint ranges as pairs of (from/to) and 0 as last element */\n};\n\nstruct nk_font_config {\n    struct nk_font_config *next; /**!< NOTE: only used internally */\n    void *ttf_blob;              /**!< pointer to loaded TTF file memory block.  * \\note not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */\n    nk_size ttf_size;            /**!< size of the loaded TTF file memory block * \\note not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */\n\n    unsigned char ttf_data_owned_by_atlas;    /**!< used inside font atlas: default to: 0*/\n    unsigned char merge_mode;                 /**!< merges this font into the last font */\n    unsigned char pixel_snap;                 /**!< align every character to pixel boundary (if true set oversample (1,1)) */\n    unsigned char oversample_v, oversample_h; /**!< rasterize at high quality for sub-pixel position */\n    unsigned char padding[3];\n\n    float size;                         /**!< baked pixel height of the font */\n    enum nk_font_coord_type coord_type; /**!< texture coordinate format with either pixel or UV coordinates */\n    struct nk_vec2 spacing;             /**!< extra pixel spacing between glyphs  */\n    const nk_rune *range;               /**!< list of unicode ranges (2 values per range, zero terminated) */\n    struct nk_baked_font *font;         /**!< font to setup in the baking process: NOTE: not needed for font atlas */\n    nk_rune fallback_glyph;             /**!< fallback glyph to use if a given rune is not found */\n    struct nk_font_config *n;\n    struct nk_font_config *p;\n};\n\nstruct nk_font_glyph {\n    nk_rune codepoint;\n    float xadvance;\n    float x0, y0, x1, y1, w, h;\n    float u0, v0, u1, v1;\n};\n\nstruct nk_font {\n    struct nk_font *next;\n    struct nk_user_font handle;\n    struct nk_baked_font info;\n    float scale;\n    struct nk_font_glyph *glyphs;\n    const struct nk_font_glyph *fallback;\n    nk_rune fallback_codepoint;\n    nk_handle texture;\n    struct nk_font_config *config;\n};\n\nenum nk_font_atlas_format {\n    NK_FONT_ATLAS_ALPHA8,\n    NK_FONT_ATLAS_RGBA32\n};\n\nstruct nk_font_atlas {\n    void *pixel;\n    int tex_width;\n    int tex_height;\n\n    struct nk_allocator permanent;\n    struct nk_allocator temporary;\n\n    struct nk_recti custom;\n    struct nk_cursor cursors[NK_CURSOR_COUNT];\n\n    int glyph_count;\n    struct nk_font_glyph *glyphs;\n    struct nk_font *default_font;\n    struct nk_font *fonts;\n    struct nk_font_config *config;\n    int font_num;\n};\n\n/** some language glyph codepoint ranges */\nNK_API const nk_rune *nk_font_default_glyph_ranges(void);\nNK_API const nk_rune *nk_font_chinese_glyph_ranges(void);\nNK_API const nk_rune *nk_font_cyrillic_glyph_ranges(void);\nNK_API const nk_rune *nk_font_korean_glyph_ranges(void);\n\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void nk_font_atlas_init_default(struct nk_font_atlas*);\n#endif\nNK_API void nk_font_atlas_init(struct nk_font_atlas*, const struct nk_allocator*);\nNK_API void nk_font_atlas_init_custom(struct nk_font_atlas*, const struct nk_allocator *persistent, const struct nk_allocator *transient);\nNK_API void nk_font_atlas_begin(struct nk_font_atlas*);\nNK_API struct nk_font_config nk_font_config(float pixel_height);\nNK_API struct nk_font *nk_font_atlas_add(struct nk_font_atlas*, const struct nk_font_config*);\n#ifdef NK_INCLUDE_DEFAULT_FONT\nNK_API struct nk_font* nk_font_atlas_add_default(struct nk_font_atlas*, float height, const struct nk_font_config*);\n#endif\nNK_API struct nk_font* nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory, nk_size size, float height, const struct nk_font_config *config);\n#ifdef NK_INCLUDE_STANDARD_IO\nNK_API struct nk_font* nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path, float height, const struct nk_font_config*);\n#endif\nNK_API struct nk_font *nk_font_atlas_add_compressed(struct nk_font_atlas*, void *memory, nk_size size, float height, const struct nk_font_config*);\nNK_API struct nk_font* nk_font_atlas_add_compressed_base85(struct nk_font_atlas*, const char *data, float height, const struct nk_font_config *config);\nNK_API const void* nk_font_atlas_bake(struct nk_font_atlas*, int *width, int *height, enum nk_font_atlas_format);\nNK_API void nk_font_atlas_end(struct nk_font_atlas*, nk_handle tex, struct nk_draw_null_texture*);\nNK_API const struct nk_font_glyph* nk_font_find_glyph(const struct nk_font*, nk_rune unicode);\nNK_API void nk_font_atlas_cleanup(struct nk_font_atlas *atlas);\nNK_API void nk_font_atlas_clear(struct nk_font_atlas*);\n\n#endif\n\n/* ==============================================================\n *\n *                          MEMORY BUFFER\n *\n * ===============================================================*/\n/**\n * \\page Memory Buffer\n * A basic (double)-buffer with linear allocation and resetting as only\n * freeing policy. The buffer's main purpose is to control all memory management\n * inside the GUI toolkit and still leave memory control as much as possible in\n * the hand of the user while also making sure the library is easy to use if\n * not as much control is needed.\n * In general all memory inside this library can be provided from the user in\n * three different ways.\n *\n * The first way and the one providing most control is by just passing a fixed\n * size memory block. In this case all control lies in the hand of the user\n * since he can exactly control where the memory comes from and how much memory\n * the library should consume. Of course using the fixed size API removes the\n * ability to automatically resize a buffer if not enough memory is provided so\n * you have to take over the resizing. While being a fixed sized buffer sounds\n * quite limiting, it is very effective in this library since the actual memory\n * consumption is quite stable and has a fixed upper bound for a lot of cases.\n *\n * If you don't want to think about how much memory the library should allocate\n * at all time or have a very dynamic UI with unpredictable memory consumption\n * habits but still want control over memory allocation you can use the dynamic\n * allocator based API. The allocator consists of two callbacks for allocating\n * and freeing memory and optional userdata so you can plugin your own allocator.\n *\n * The final and easiest way can be used by defining\n * NK_INCLUDE_DEFAULT_ALLOCATOR which uses the standard library memory\n * allocation functions malloc and free and takes over complete control over\n * memory in this library.\n */\n\nstruct nk_memory_status {\n    void *memory;\n    unsigned int type;\n    nk_size size;\n    nk_size allocated;\n    nk_size needed;\n    nk_size calls;\n};\n\nenum nk_allocation_type {\n    NK_BUFFER_FIXED,\n    NK_BUFFER_DYNAMIC\n};\n\nenum nk_buffer_allocation_type {\n    NK_BUFFER_FRONT,\n    NK_BUFFER_BACK,\n    NK_BUFFER_MAX\n};\n\nstruct nk_buffer_marker {\n    nk_bool active;\n    nk_size offset;\n};\n\nstruct nk_memory {void *ptr;nk_size size;};\nstruct nk_buffer {\n    struct nk_buffer_marker marker[NK_BUFFER_MAX]; /**!< buffer marker to free a buffer to a certain offset */\n    struct nk_allocator pool;     /**!< allocator callback for dynamic buffers */\n    enum nk_allocation_type type; /**!< memory management type */\n    struct nk_memory memory;      /**!< memory and size of the current memory block */\n    float grow_factor;            /**!< growing factor for dynamic memory management */\n    nk_size allocated;            /**!< total amount of memory allocated */\n    nk_size needed;               /**!< totally consumed memory given that enough memory is present */\n    nk_size calls;                /**!< number of allocation calls */\n    nk_size size;                 /**!< current size of the buffer */\n};\n\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void nk_buffer_init_default(struct nk_buffer*);\n#endif\nNK_API void nk_buffer_init(struct nk_buffer*, const struct nk_allocator*, nk_size size);\nNK_API void nk_buffer_init_fixed(struct nk_buffer*, void *memory, nk_size size);\nNK_API void nk_buffer_info(struct nk_memory_status*, const struct nk_buffer*);\nNK_API void nk_buffer_push(struct nk_buffer*, enum nk_buffer_allocation_type type, const void *memory, nk_size size, nk_size align);\nNK_API void nk_buffer_mark(struct nk_buffer*, enum nk_buffer_allocation_type type);\nNK_API void nk_buffer_reset(struct nk_buffer*, enum nk_buffer_allocation_type type);\nNK_API void nk_buffer_clear(struct nk_buffer*);\nNK_API void nk_buffer_free(struct nk_buffer*);\nNK_API void *nk_buffer_memory(struct nk_buffer*);\nNK_API const void *nk_buffer_memory_const(const struct nk_buffer*);\nNK_API nk_size nk_buffer_total(const struct nk_buffer*);\n\n/* ==============================================================\n *\n *                          STRING\n *\n * ===============================================================*/\n/**  Basic string buffer which is only used in context with the text editor\n *  to manage and manipulate dynamic or fixed size string content. This is _NOT_\n *  the default string handling method. The only instance you should have any contact\n *  with this API is if you interact with an `nk_text_edit` object inside one of the\n *  copy and paste functions and even there only for more advanced cases. */\nstruct nk_str {\n    struct nk_buffer buffer;\n    int len; /**!< in codepoints/runes/glyphs */\n};\n\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void nk_str_init_default(struct nk_str*);\n#endif\nNK_API void nk_str_init(struct nk_str*, const struct nk_allocator*, nk_size size);\nNK_API void nk_str_init_fixed(struct nk_str*, void *memory, nk_size size);\nNK_API void nk_str_clear(struct nk_str*);\nNK_API void nk_str_free(struct nk_str*);\n\nNK_API int nk_str_append_text_char(struct nk_str*, const char*, int);\nNK_API int nk_str_append_str_char(struct nk_str*, const char*);\nNK_API int nk_str_append_text_utf8(struct nk_str*, const char*, int);\nNK_API int nk_str_append_str_utf8(struct nk_str*, const char*);\nNK_API int nk_str_append_text_runes(struct nk_str*, const nk_rune*, int);\nNK_API int nk_str_append_str_runes(struct nk_str*, const nk_rune*);\n\nNK_API int nk_str_insert_at_char(struct nk_str*, int pos, const char*, int);\nNK_API int nk_str_insert_at_rune(struct nk_str*, int pos, const char*, int);\n\nNK_API int nk_str_insert_text_char(struct nk_str*, int pos, const char*, int);\nNK_API int nk_str_insert_str_char(struct nk_str*, int pos, const char*);\nNK_API int nk_str_insert_text_utf8(struct nk_str*, int pos, const char*, int);\nNK_API int nk_str_insert_str_utf8(struct nk_str*, int pos, const char*);\nNK_API int nk_str_insert_text_runes(struct nk_str*, int pos, const nk_rune*, int);\nNK_API int nk_str_insert_str_runes(struct nk_str*, int pos, const nk_rune*);\n\nNK_API void nk_str_remove_chars(struct nk_str*, int len);\nNK_API void nk_str_remove_runes(struct nk_str *str, int len);\nNK_API void nk_str_delete_chars(struct nk_str*, int pos, int len);\nNK_API void nk_str_delete_runes(struct nk_str*, int pos, int len);\n\nNK_API char *nk_str_at_char(struct nk_str*, int pos);\nNK_API char *nk_str_at_rune(struct nk_str*, int pos, nk_rune *unicode, int *len);\nNK_API nk_rune nk_str_rune_at(const struct nk_str*, int pos);\nNK_API const char *nk_str_at_char_const(const struct nk_str*, int pos);\nNK_API const char *nk_str_at_const(const struct nk_str*, int pos, nk_rune *unicode, int *len);\n\nNK_API char *nk_str_get(struct nk_str*);\nNK_API const char *nk_str_get_const(const struct nk_str*);\nNK_API int nk_str_len(const struct nk_str*);\nNK_API int nk_str_len_char(const struct nk_str*);\n\n/* ===============================================================\n *\n *                      TEXT EDITOR\n *\n * ===============================================================*/\n/**\n * \\page Text Editor\n * Editing text in this library is handled by either `nk_edit_string` or\n * `nk_edit_buffer`. But like almost everything in this library there are multiple\n * ways of doing it and a balance between control and ease of use with memory\n * as well as functionality controlled by flags.\n *\n * This library generally allows three different levels of memory control:\n * First of is the most basic way of just providing a simple char array with\n * string length. This method is probably the easiest way of handling simple\n * user text input. Main upside is complete control over memory while the biggest\n * downside in comparison with the other two approaches is missing undo/redo.\n *\n * For UIs that require undo/redo the second way was created. It is based on\n * a fixed size nk_text_edit struct, which has an internal undo/redo stack.\n * This is mainly useful if you want something more like a text editor but don't want\n * to have a dynamically growing buffer.\n *\n * The final way is using a dynamically growing nk_text_edit struct, which\n * has both a default version if you don't care where memory comes from and an\n * allocator version if you do. While the text editor is quite powerful for its\n * complexity I would not recommend editing gigabytes of data with it.\n * It is rather designed for uses cases which make sense for a GUI library not for\n * an full blown text editor.\n */\n\n#ifndef NK_TEXTEDIT_UNDOSTATECOUNT\n#define NK_TEXTEDIT_UNDOSTATECOUNT     99\n#endif\n\n#ifndef NK_TEXTEDIT_UNDOCHARCOUNT\n#define NK_TEXTEDIT_UNDOCHARCOUNT      999\n#endif\n\nstruct nk_text_edit;\nstruct nk_clipboard {\n    nk_handle userdata;\n    nk_plugin_paste paste;\n    nk_plugin_copy copy;\n};\n\nstruct nk_text_undo_record {\n   int where;\n   short insert_length;\n   short delete_length;\n   short char_storage;\n};\n\nstruct nk_text_undo_state {\n   struct nk_text_undo_record undo_rec[NK_TEXTEDIT_UNDOSTATECOUNT];\n   nk_rune undo_char[NK_TEXTEDIT_UNDOCHARCOUNT];\n   short undo_point;\n   short redo_point;\n   short undo_char_point;\n   short redo_char_point;\n};\n\nenum nk_text_edit_type {\n    NK_TEXT_EDIT_SINGLE_LINE,\n    NK_TEXT_EDIT_MULTI_LINE\n};\n\nenum nk_text_edit_mode {\n    NK_TEXT_EDIT_MODE_VIEW,\n    NK_TEXT_EDIT_MODE_INSERT,\n    NK_TEXT_EDIT_MODE_REPLACE\n};\n\nstruct nk_text_edit {\n    struct nk_clipboard clip;\n    struct nk_str string;\n    nk_plugin_filter filter;\n    struct nk_vec2 scrollbar;\n\n    int cursor;\n    int select_start;\n    int select_end;\n    unsigned char mode;\n    unsigned char cursor_at_end_of_line;\n    unsigned char initialized;\n    unsigned char has_preferred_x;\n    unsigned char single_line;\n    unsigned char active;\n    unsigned char padding1;\n    float preferred_x;\n    struct nk_text_undo_state undo;\n};\n\n/** filter function */\nNK_API nk_bool nk_filter_default(const struct nk_text_edit*, nk_rune unicode);\nNK_API nk_bool nk_filter_ascii(const struct nk_text_edit*, nk_rune unicode);\nNK_API nk_bool nk_filter_float(const struct nk_text_edit*, nk_rune unicode);\nNK_API nk_bool nk_filter_decimal(const struct nk_text_edit*, nk_rune unicode);\nNK_API nk_bool nk_filter_hex(const struct nk_text_edit*, nk_rune unicode);\nNK_API nk_bool nk_filter_oct(const struct nk_text_edit*, nk_rune unicode);\nNK_API nk_bool nk_filter_binary(const struct nk_text_edit*, nk_rune unicode);\n\n/** text editor */\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void nk_textedit_init_default(struct nk_text_edit*);\n#endif\nNK_API void nk_textedit_init(struct nk_text_edit*, const struct nk_allocator*, nk_size size);\nNK_API void nk_textedit_init_fixed(struct nk_text_edit*, void *memory, nk_size size);\nNK_API void nk_textedit_free(struct nk_text_edit*);\nNK_API void nk_textedit_text(struct nk_text_edit*, const char*, int total_len);\nNK_API void nk_textedit_delete(struct nk_text_edit*, int where, int len);\nNK_API void nk_textedit_delete_selection(struct nk_text_edit*);\nNK_API void nk_textedit_select_all(struct nk_text_edit*);\nNK_API nk_bool nk_textedit_cut(struct nk_text_edit*);\nNK_API nk_bool nk_textedit_paste(struct nk_text_edit*, char const*, int len);\nNK_API void nk_textedit_undo(struct nk_text_edit*);\nNK_API void nk_textedit_redo(struct nk_text_edit*);\n\n/* ===============================================================\n *\n *                          DRAWING\n *\n * ===============================================================*/\n/**\n * \\page Drawing\n * This library was designed to be render backend agnostic so it does\n * not draw anything to screen. Instead all drawn shapes, widgets\n * are made of, are buffered into memory and make up a command queue.\n * Each frame therefore fills the command buffer with draw commands\n * that then need to be executed by the user and his own render backend.\n * After that the command buffer needs to be cleared and a new frame can be\n * started. It is probably important to note that the command buffer is the main\n * drawing API and the optional vertex buffer API only takes this format and\n * converts it into a hardware accessible format.\n *\n * To use the command queue to draw your own widgets you can access the\n * command buffer of each window by calling `nk_window_get_canvas` after\n * previously having called `nk_begin`:\n *\n * ```c\n *     void draw_red_rectangle_widget(struct nk_context *ctx)\n *     {\n *         struct nk_command_buffer *canvas;\n *         struct nk_input *input = &ctx->input;\n *         canvas = nk_window_get_canvas(ctx);\n *\n *         struct nk_rect space;\n *         enum nk_widget_layout_states state;\n *         state = nk_widget(&space, ctx);\n *         if (!state) return;\n *\n *         if (state != NK_WIDGET_ROM)\n *             update_your_widget_by_user_input(...);\n *         nk_fill_rect(canvas, space, 0, nk_rgb(255,0,0));\n *     }\n *\n *     if (nk_begin(...)) {\n *         nk_layout_row_dynamic(ctx, 25, 1);\n *         draw_red_rectangle_widget(ctx);\n *     }\n *     nk_end(..)\n *\n * ```\n * Important to know if you want to create your own widgets is the `nk_widget`\n * call. It allocates space on the panel reserved for this widget to be used,\n * but also returns the state of the widget space. If your widget is not seen and does\n * not have to be updated it is '0' and you can just return. If it only has\n * to be drawn the state will be `NK_WIDGET_ROM` otherwise you can do both\n * update and draw your widget. The reason for separating is to only draw and\n * update what is actually necessary which is crucial for performance.\n */\n\nenum nk_command_type {\n    NK_COMMAND_NOP,\n    NK_COMMAND_SCISSOR,\n    NK_COMMAND_LINE,\n    NK_COMMAND_CURVE,\n    NK_COMMAND_RECT,\n    NK_COMMAND_RECT_FILLED,\n    NK_COMMAND_RECT_MULTI_COLOR,\n    NK_COMMAND_CIRCLE,\n    NK_COMMAND_CIRCLE_FILLED,\n    NK_COMMAND_ARC,\n    NK_COMMAND_ARC_FILLED,\n    NK_COMMAND_TRIANGLE,\n    NK_COMMAND_TRIANGLE_FILLED,\n    NK_COMMAND_POLYGON,\n    NK_COMMAND_POLYGON_FILLED,\n    NK_COMMAND_POLYLINE,\n    NK_COMMAND_TEXT,\n    NK_COMMAND_IMAGE,\n    NK_COMMAND_CUSTOM\n};\n\n /** command base and header of every command inside the buffer */\nstruct nk_command {\n    enum nk_command_type type;\n    nk_size next;\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    nk_handle userdata;\n#endif\n};\n\nstruct nk_command_scissor {\n    struct nk_command header;\n    short x, y;\n    unsigned short w, h;\n};\n\nstruct nk_command_line {\n    struct nk_command header;\n    unsigned short line_thickness;\n    struct nk_vec2i begin;\n    struct nk_vec2i end;\n    struct nk_color color;\n};\n\nstruct nk_command_curve {\n    struct nk_command header;\n    unsigned short line_thickness;\n    struct nk_vec2i begin;\n    struct nk_vec2i end;\n    struct nk_vec2i ctrl[2];\n    struct nk_color color;\n};\n\nstruct nk_command_rect {\n    struct nk_command header;\n    unsigned short rounding;\n    unsigned short line_thickness;\n    short x, y;\n    unsigned short w, h;\n    struct nk_color color;\n};\n\nstruct nk_command_rect_filled {\n    struct nk_command header;\n    unsigned short rounding;\n    short x, y;\n    unsigned short w, h;\n    struct nk_color color;\n};\n\nstruct nk_command_rect_multi_color {\n    struct nk_command header;\n    short x, y;\n    unsigned short w, h;\n    struct nk_color left;\n    struct nk_color top;\n    struct nk_color bottom;\n    struct nk_color right;\n};\n\nstruct nk_command_triangle {\n    struct nk_command header;\n    unsigned short line_thickness;\n    struct nk_vec2i a;\n    struct nk_vec2i b;\n    struct nk_vec2i c;\n    struct nk_color color;\n};\n\nstruct nk_command_triangle_filled {\n    struct nk_command header;\n    struct nk_vec2i a;\n    struct nk_vec2i b;\n    struct nk_vec2i c;\n    struct nk_color color;\n};\n\nstruct nk_command_circle {\n    struct nk_command header;\n    short x, y;\n    unsigned short line_thickness;\n    unsigned short w, h;\n    struct nk_color color;\n};\n\nstruct nk_command_circle_filled {\n    struct nk_command header;\n    short x, y;\n    unsigned short w, h;\n    struct nk_color color;\n};\n\nstruct nk_command_arc {\n    struct nk_command header;\n    short cx, cy;\n    unsigned short r;\n    unsigned short line_thickness;\n    float a[2];\n    struct nk_color color;\n};\n\nstruct nk_command_arc_filled {\n    struct nk_command header;\n    short cx, cy;\n    unsigned short r;\n    float a[2];\n    struct nk_color color;\n};\n\nstruct nk_command_polygon {\n    struct nk_command header;\n    struct nk_color color;\n    unsigned short line_thickness;\n    unsigned short point_count;\n    struct nk_vec2i points[1];\n};\n\nstruct nk_command_polygon_filled {\n    struct nk_command header;\n    struct nk_color color;\n    unsigned short point_count;\n    struct nk_vec2i points[1];\n};\n\nstruct nk_command_polyline {\n    struct nk_command header;\n    struct nk_color color;\n    unsigned short line_thickness;\n    unsigned short point_count;\n    struct nk_vec2i points[1];\n};\n\nstruct nk_command_image {\n    struct nk_command header;\n    short x, y;\n    unsigned short w, h;\n    struct nk_image img;\n    struct nk_color col;\n};\n\ntypedef void (*nk_command_custom_callback)(void *canvas, short x,short y,\n    unsigned short w, unsigned short h, nk_handle callback_data);\nstruct nk_command_custom {\n    struct nk_command header;\n    short x, y;\n    unsigned short w, h;\n    nk_handle callback_data;\n    nk_command_custom_callback callback;\n};\n\nstruct nk_command_text {\n    struct nk_command header;\n    const struct nk_user_font *font;\n    struct nk_color background;\n    struct nk_color foreground;\n    short x, y;\n    unsigned short w, h;\n    float height;\n    int length;\n    char string[2];\n};\n\nenum nk_command_clipping {\n    NK_CLIPPING_OFF = nk_false,\n    NK_CLIPPING_ON = nk_true\n};\n\nstruct nk_command_buffer {\n    struct nk_buffer *base;\n    struct nk_rect clip;\n    int use_clipping;\n    nk_handle userdata;\n    nk_size begin, end, last;\n};\n\n/** shape outlines */\nNK_API void nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, float x1, float y1, float line_thickness, struct nk_color);\nNK_API void nk_stroke_curve(struct nk_command_buffer*, float, float, float, float, float, float, float, float, float line_thickness, struct nk_color);\nNK_API void nk_stroke_rect(struct nk_command_buffer*, struct nk_rect, float rounding, float line_thickness, struct nk_color);\nNK_API void nk_stroke_circle(struct nk_command_buffer*, struct nk_rect, float line_thickness, struct nk_color);\nNK_API void nk_stroke_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, float line_thickness, struct nk_color);\nNK_API void nk_stroke_triangle(struct nk_command_buffer*, float, float, float, float, float, float, float line_thichness, struct nk_color);\nNK_API void nk_stroke_polyline(struct nk_command_buffer*, const float *points, int point_count, float line_thickness, struct nk_color col);\nNK_API void nk_stroke_polygon(struct nk_command_buffer*, const float *points, int point_count, float line_thickness, struct nk_color);\n\n/** filled shades */\nNK_API void nk_fill_rect(struct nk_command_buffer*, struct nk_rect, float rounding, struct nk_color);\nNK_API void nk_fill_rect_multi_color(struct nk_command_buffer*, struct nk_rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom);\nNK_API void nk_fill_circle(struct nk_command_buffer*, struct nk_rect, struct nk_color);\nNK_API void nk_fill_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, struct nk_color);\nNK_API void nk_fill_triangle(struct nk_command_buffer*, float x0, float y0, float x1, float y1, float x2, float y2, struct nk_color);\nNK_API void nk_fill_polygon(struct nk_command_buffer*, const float *points, int point_count, struct nk_color);\n\n/** misc */\nNK_API void nk_draw_image(struct nk_command_buffer*, struct nk_rect, const struct nk_image*, struct nk_color);\nNK_API void nk_draw_nine_slice(struct nk_command_buffer*, struct nk_rect, const struct nk_nine_slice*, struct nk_color);\nNK_API void nk_draw_text(struct nk_command_buffer*, struct nk_rect, const char *text, int len, const struct nk_user_font*, struct nk_color, struct nk_color);\nNK_API void nk_push_scissor(struct nk_command_buffer*, struct nk_rect);\nNK_API void nk_push_custom(struct nk_command_buffer*, struct nk_rect, nk_command_custom_callback, nk_handle usr);\n\n/* ===============================================================\n *\n *                          INPUT\n *\n * ===============================================================*/\nstruct nk_mouse_button {\n    nk_bool down;\n    unsigned int clicked;\n    struct nk_vec2 clicked_pos;\n};\nstruct nk_mouse {\n    struct nk_mouse_button buttons[NK_BUTTON_MAX];\n    struct nk_vec2 pos;\n#ifdef NK_BUTTON_TRIGGER_ON_RELEASE\n    struct nk_vec2 down_pos;\n#endif\n    struct nk_vec2 prev;\n    struct nk_vec2 delta;\n    struct nk_vec2 scroll_delta;\n    unsigned char grab;\n    unsigned char grabbed;\n    unsigned char ungrab;\n};\n\nstruct nk_key {\n    nk_bool down;\n    unsigned int clicked;\n};\nstruct nk_keyboard {\n    struct nk_key keys[NK_KEY_MAX];\n    char text[NK_INPUT_MAX];\n    int text_len;\n};\n\nstruct nk_input {\n    struct nk_keyboard keyboard;\n    struct nk_mouse mouse;\n};\n\nNK_API nk_bool nk_input_has_mouse_click(const struct nk_input*, enum nk_buttons);\nNK_API nk_bool nk_input_has_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);\nNK_API nk_bool nk_input_has_mouse_click_in_button_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);\nNK_API nk_bool nk_input_has_mouse_click_down_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect, nk_bool down);\nNK_API nk_bool nk_input_is_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);\nNK_API nk_bool nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, struct nk_rect b, nk_bool down);\nNK_API nk_bool nk_input_any_mouse_click_in_rect(const struct nk_input*, struct nk_rect);\nNK_API nk_bool nk_input_is_mouse_prev_hovering_rect(const struct nk_input*, struct nk_rect);\nNK_API nk_bool nk_input_is_mouse_hovering_rect(const struct nk_input*, struct nk_rect);\nNK_API nk_bool nk_input_is_mouse_moved(const struct nk_input*);\nNK_API nk_bool nk_input_mouse_clicked(const struct nk_input*, enum nk_buttons, struct nk_rect);\nNK_API nk_bool nk_input_is_mouse_down(const struct nk_input*, enum nk_buttons);\nNK_API nk_bool nk_input_is_mouse_pressed(const struct nk_input*, enum nk_buttons);\nNK_API nk_bool nk_input_is_mouse_released(const struct nk_input*, enum nk_buttons);\nNK_API nk_bool nk_input_is_key_pressed(const struct nk_input*, enum nk_keys);\nNK_API nk_bool nk_input_is_key_released(const struct nk_input*, enum nk_keys);\nNK_API nk_bool nk_input_is_key_down(const struct nk_input*, enum nk_keys);\n\n/* ===============================================================\n *\n *                          DRAW LIST\n *\n * ===============================================================*/\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n/**\n * \\page \"Draw List\"\n * The optional vertex buffer draw list provides a 2D drawing context\n * with antialiasing functionality which takes basic filled or outlined shapes\n * or a path and outputs vertexes, elements and draw commands.\n * The actual draw list API is not required to be used directly while using this\n * library since converting the default library draw command output is done by\n * just calling `nk_convert` but I decided to still make this library accessible\n * since it can be useful.\n *\n * The draw list is based on a path buffering and polygon and polyline\n * rendering API which allows a lot of ways to draw 2D content to screen.\n * In fact it is probably more powerful than needed but allows even more crazy\n * things than this library provides by default.\n */\n\n#ifdef NK_UINT_DRAW_INDEX\ntypedef nk_uint nk_draw_index;\n#else\ntypedef nk_ushort nk_draw_index;\n#endif\nenum nk_draw_list_stroke {\n    NK_STROKE_OPEN = nk_false, /***< build up path has no connection back to the beginning */\n    NK_STROKE_CLOSED = nk_true /***< build up path has a connection back to the beginning */\n};\n\nenum nk_draw_vertex_layout_attribute {\n    NK_VERTEX_POSITION,\n    NK_VERTEX_COLOR,\n    NK_VERTEX_TEXCOORD,\n    NK_VERTEX_ATTRIBUTE_COUNT\n};\n\nenum nk_draw_vertex_layout_format {\n    NK_FORMAT_SCHAR,\n    NK_FORMAT_SSHORT,\n    NK_FORMAT_SINT,\n    NK_FORMAT_UCHAR,\n    NK_FORMAT_USHORT,\n    NK_FORMAT_UINT,\n    NK_FORMAT_FLOAT,\n    NK_FORMAT_DOUBLE,\n\nNK_FORMAT_COLOR_BEGIN,\n    NK_FORMAT_R8G8B8 = NK_FORMAT_COLOR_BEGIN,\n    NK_FORMAT_R16G15B16,\n    NK_FORMAT_R32G32B32,\n\n    NK_FORMAT_R8G8B8A8,\n    NK_FORMAT_B8G8R8A8,\n    NK_FORMAT_R16G15B16A16,\n    NK_FORMAT_R32G32B32A32,\n    NK_FORMAT_R32G32B32A32_FLOAT,\n    NK_FORMAT_R32G32B32A32_DOUBLE,\n\n    NK_FORMAT_RGB32,\n    NK_FORMAT_RGBA32,\nNK_FORMAT_COLOR_END = NK_FORMAT_RGBA32,\n    NK_FORMAT_COUNT\n};\n\n#define NK_VERTEX_LAYOUT_END NK_VERTEX_ATTRIBUTE_COUNT,NK_FORMAT_COUNT,0\nstruct nk_draw_vertex_layout_element {\n    enum nk_draw_vertex_layout_attribute attribute;\n    enum nk_draw_vertex_layout_format format;\n    nk_size offset;\n};\n\nstruct nk_draw_command {\n    unsigned int elem_count; /**< number of elements in the current draw batch */\n    struct nk_rect clip_rect; /**< current screen clipping rectangle */\n    nk_handle texture; /**< current texture to set */\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    nk_handle userdata;\n#endif\n};\n\nstruct nk_draw_list {\n    struct nk_rect clip_rect;\n    struct nk_vec2 circle_vtx[12];\n    struct nk_convert_config config;\n\n    struct nk_buffer *buffer;\n    struct nk_buffer *vertices;\n    struct nk_buffer *elements;\n\n    unsigned int element_count;\n    unsigned int vertex_count;\n    unsigned int cmd_count;\n    nk_size cmd_offset;\n\n    unsigned int path_count;\n    unsigned int path_offset;\n\n    enum nk_anti_aliasing line_AA;\n    enum nk_anti_aliasing shape_AA;\n\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    nk_handle userdata;\n#endif\n};\n\n/* draw list */\nNK_API void nk_draw_list_init(struct nk_draw_list*);\nNK_API void nk_draw_list_setup(struct nk_draw_list*, const struct nk_convert_config*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, enum nk_anti_aliasing line_aa,enum nk_anti_aliasing shape_aa);\n\n/* drawing */\n#define nk_draw_list_foreach(cmd, can, b) for((cmd)=nk__draw_list_begin(can, b); (cmd)!=0; (cmd)=nk__draw_list_next(cmd, b, can))\nNK_API const struct nk_draw_command* nk__draw_list_begin(const struct nk_draw_list*, const struct nk_buffer*);\nNK_API const struct nk_draw_command* nk__draw_list_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_draw_list*);\nNK_API const struct nk_draw_command* nk__draw_list_end(const struct nk_draw_list*, const struct nk_buffer*);\n\n/* path */\nNK_API void nk_draw_list_path_clear(struct nk_draw_list*);\nNK_API void nk_draw_list_path_line_to(struct nk_draw_list*, struct nk_vec2 pos);\nNK_API void nk_draw_list_path_arc_to_fast(struct nk_draw_list*, struct nk_vec2 center, float radius, int a_min, int a_max);\nNK_API void nk_draw_list_path_arc_to(struct nk_draw_list*, struct nk_vec2 center, float radius, float a_min, float a_max, unsigned int segments);\nNK_API void nk_draw_list_path_rect_to(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, float rounding);\nNK_API void nk_draw_list_path_curve_to(struct nk_draw_list*, struct nk_vec2 p2, struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments);\nNK_API void nk_draw_list_path_fill(struct nk_draw_list*, struct nk_color);\nNK_API void nk_draw_list_path_stroke(struct nk_draw_list*, struct nk_color, enum nk_draw_list_stroke closed, float thickness);\n\n/* stroke */\nNK_API void nk_draw_list_stroke_line(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_color, float thickness);\nNK_API void nk_draw_list_stroke_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding, float thickness);\nNK_API void nk_draw_list_stroke_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color, float thickness);\nNK_API void nk_draw_list_stroke_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color, unsigned int segs, float thickness);\nNK_API void nk_draw_list_stroke_curve(struct nk_draw_list*, struct nk_vec2 p0, struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1, struct nk_color, unsigned int segments, float thickness);\nNK_API void nk_draw_list_stroke_poly_line(struct nk_draw_list*, const struct nk_vec2 *pnts, const unsigned int cnt, struct nk_color, enum nk_draw_list_stroke, float thickness, enum nk_anti_aliasing);\n\n/* fill */\nNK_API void nk_draw_list_fill_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding);\nNK_API void nk_draw_list_fill_rect_multi_color(struct nk_draw_list*, struct nk_rect rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom);\nNK_API void nk_draw_list_fill_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color);\nNK_API void nk_draw_list_fill_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color col, unsigned int segs);\nNK_API void nk_draw_list_fill_poly_convex(struct nk_draw_list*, const struct nk_vec2 *points, const unsigned int count, struct nk_color, enum nk_anti_aliasing);\n\n/* misc */\nNK_API void nk_draw_list_add_image(struct nk_draw_list*, struct nk_image texture, struct nk_rect rect, struct nk_color);\nNK_API void nk_draw_list_add_text(struct nk_draw_list*, const struct nk_user_font*, struct nk_rect, const char *text, int len, float font_height, struct nk_color);\n#ifdef NK_INCLUDE_COMMAND_USERDATA\nNK_API void nk_draw_list_push_userdata(struct nk_draw_list*, nk_handle userdata);\n#endif\n\n#endif\n\n/* ===============================================================\n *\n *                          GUI\n *\n * ===============================================================*/\nenum nk_style_item_type {\n    NK_STYLE_ITEM_COLOR,\n    NK_STYLE_ITEM_IMAGE,\n    NK_STYLE_ITEM_NINE_SLICE\n};\n\nunion nk_style_item_data {\n    struct nk_color color;\n    struct nk_image image;\n    struct nk_nine_slice slice;\n};\n\nstruct nk_style_item {\n    enum nk_style_item_type type;\n    union nk_style_item_data data;\n};\n\nstruct nk_style_text {\n    struct nk_color color;\n    struct nk_vec2 padding;\n    float color_factor;\n    float disabled_factor;\n};\n\nstruct nk_style_button {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n    float color_factor_background;\n\n    /* text */\n    struct nk_color text_background;\n    struct nk_color text_normal;\n    struct nk_color text_hover;\n    struct nk_color text_active;\n    nk_flags text_alignment;\n    float color_factor_text;\n\n    /* properties */\n    float border;\n    float rounding;\n    struct nk_vec2 padding;\n    struct nk_vec2 image_padding;\n    struct nk_vec2 touch_padding;\n    float disabled_factor;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle userdata);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle userdata);\n};\n\nstruct nk_style_toggle {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* cursor */\n    struct nk_style_item cursor_normal;\n    struct nk_style_item cursor_hover;\n\n    /* text */\n    struct nk_color text_normal;\n    struct nk_color text_hover;\n    struct nk_color text_active;\n    struct nk_color text_background;\n    nk_flags text_alignment;\n\n    /* properties */\n    struct nk_vec2 padding;\n    struct nk_vec2 touch_padding;\n    float spacing;\n    float border;\n    float color_factor;\n    float disabled_factor;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_selectable {\n    /* background (inactive) */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item pressed;\n\n    /* background (active) */\n    struct nk_style_item normal_active;\n    struct nk_style_item hover_active;\n    struct nk_style_item pressed_active;\n\n    /* text color (inactive) */\n    struct nk_color text_normal;\n    struct nk_color text_hover;\n    struct nk_color text_pressed;\n\n    /* text color (active) */\n    struct nk_color text_normal_active;\n    struct nk_color text_hover_active;\n    struct nk_color text_pressed_active;\n    struct nk_color text_background;\n    nk_flags text_alignment;\n\n    /* properties */\n    float rounding;\n    struct nk_vec2 padding;\n    struct nk_vec2 touch_padding;\n    struct nk_vec2 image_padding;\n    float color_factor;\n    float disabled_factor;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_slider {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* background bar */\n    struct nk_color bar_normal;\n    struct nk_color bar_hover;\n    struct nk_color bar_active;\n    struct nk_color bar_filled;\n\n    /* cursor */\n    struct nk_style_item cursor_normal;\n    struct nk_style_item cursor_hover;\n    struct nk_style_item cursor_active;\n\n    /* properties */\n    float border;\n    float rounding;\n    float bar_height;\n    struct nk_vec2 padding;\n    struct nk_vec2 spacing;\n    struct nk_vec2 cursor_size;\n    float color_factor;\n    float disabled_factor;\n\n    /* optional buttons */\n    int show_buttons;\n    struct nk_style_button inc_button;\n    struct nk_style_button dec_button;\n    enum nk_symbol_type inc_symbol;\n    enum nk_symbol_type dec_symbol;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_knob {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* knob */\n    struct nk_color knob_normal;\n    struct nk_color knob_hover;\n    struct nk_color knob_active;\n    struct nk_color knob_border_color;\n\n    /* cursor */\n    struct nk_color cursor_normal;\n    struct nk_color cursor_hover;\n    struct nk_color cursor_active;\n\n    /* properties */\n    float border;\n    float knob_border;\n    struct nk_vec2 padding;\n    struct nk_vec2 spacing;\n    float cursor_width;\n    float color_factor;\n    float disabled_factor;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_progress {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* cursor */\n    struct nk_style_item cursor_normal;\n    struct nk_style_item cursor_hover;\n    struct nk_style_item cursor_active;\n    struct nk_color cursor_border_color;\n\n    /* properties */\n    float rounding;\n    float border;\n    float cursor_border;\n    float cursor_rounding;\n    struct nk_vec2 padding;\n    float color_factor;\n    float disabled_factor;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_scrollbar {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* cursor */\n    struct nk_style_item cursor_normal;\n    struct nk_style_item cursor_hover;\n    struct nk_style_item cursor_active;\n    struct nk_color cursor_border_color;\n\n    /* properties */\n    float border;\n    float rounding;\n    float border_cursor;\n    float rounding_cursor;\n    struct nk_vec2 padding;\n    float color_factor;\n    float disabled_factor;\n\n    /* optional buttons */\n    int show_buttons;\n    struct nk_style_button inc_button;\n    struct nk_style_button dec_button;\n    enum nk_symbol_type inc_symbol;\n    enum nk_symbol_type dec_symbol;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_edit {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n    struct nk_style_scrollbar scrollbar;\n\n    /* cursor  */\n    struct nk_color cursor_normal;\n    struct nk_color cursor_hover;\n    struct nk_color cursor_text_normal;\n    struct nk_color cursor_text_hover;\n\n    /* text (unselected) */\n    struct nk_color text_normal;\n    struct nk_color text_hover;\n    struct nk_color text_active;\n\n    /* text (selected) */\n    struct nk_color selected_normal;\n    struct nk_color selected_hover;\n    struct nk_color selected_text_normal;\n    struct nk_color selected_text_hover;\n\n    /* properties */\n    float border;\n    float rounding;\n    float cursor_size;\n    struct nk_vec2 scrollbar_size;\n    struct nk_vec2 padding;\n    float row_padding;\n    float color_factor;\n    float disabled_factor;\n};\n\nstruct nk_style_property {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* text */\n    struct nk_color label_normal;\n    struct nk_color label_hover;\n    struct nk_color label_active;\n\n    /* symbols */\n    enum nk_symbol_type sym_left;\n    enum nk_symbol_type sym_right;\n\n    /* properties */\n    float border;\n    float rounding;\n    struct nk_vec2 padding;\n    float color_factor;\n    float disabled_factor;\n\n    struct nk_style_edit edit;\n    struct nk_style_button inc_button;\n    struct nk_style_button dec_button;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_chart {\n    /* colors */\n    struct nk_style_item background;\n    struct nk_color border_color;\n    struct nk_color selected_color;\n    struct nk_color color;\n\n    /* properties */\n    float border;\n    float rounding;\n    struct nk_vec2 padding;\n    float color_factor;\n    float disabled_factor;\n    nk_bool show_markers;\n};\n\nstruct nk_style_combo {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* label */\n    struct nk_color label_normal;\n    struct nk_color label_hover;\n    struct nk_color label_active;\n\n    /* symbol */\n    struct nk_color symbol_normal;\n    struct nk_color symbol_hover;\n    struct nk_color symbol_active;\n\n    /* button */\n    struct nk_style_button button;\n    enum nk_symbol_type sym_normal;\n    enum nk_symbol_type sym_hover;\n    enum nk_symbol_type sym_active;\n\n    /* properties */\n    float border;\n    float rounding;\n    struct nk_vec2 content_padding;\n    struct nk_vec2 button_padding;\n    struct nk_vec2 spacing;\n    float color_factor;\n    float disabled_factor;\n};\n\nstruct nk_style_tab {\n    /* background */\n    struct nk_style_item background;\n    struct nk_color border_color;\n    struct nk_color text;\n\n    /* button */\n    struct nk_style_button tab_maximize_button;\n    struct nk_style_button tab_minimize_button;\n    struct nk_style_button node_maximize_button;\n    struct nk_style_button node_minimize_button;\n    enum nk_symbol_type sym_minimize;\n    enum nk_symbol_type sym_maximize;\n\n    /* properties */\n    float border;\n    float rounding;\n    float indent;\n    struct nk_vec2 padding;\n    struct nk_vec2 spacing;\n    float color_factor;\n    float disabled_factor;\n};\n\nenum nk_style_header_align {\n    NK_HEADER_LEFT,\n    NK_HEADER_RIGHT\n};\nstruct nk_style_window_header {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n\n    /* button */\n    struct nk_style_button close_button;\n    struct nk_style_button minimize_button;\n    enum nk_symbol_type close_symbol;\n    enum nk_symbol_type minimize_symbol;\n    enum nk_symbol_type maximize_symbol;\n\n    /* title */\n    struct nk_color label_normal;\n    struct nk_color label_hover;\n    struct nk_color label_active;\n\n    /* properties */\n    enum nk_style_header_align align;\n    struct nk_vec2 padding;\n    struct nk_vec2 label_padding;\n    struct nk_vec2 spacing;\n};\n\nstruct nk_style_window {\n    struct nk_style_window_header header;\n    struct nk_style_item fixed_background;\n    struct nk_color background;\n\n    struct nk_color border_color;\n    struct nk_color popup_border_color;\n    struct nk_color combo_border_color;\n    struct nk_color contextual_border_color;\n    struct nk_color menu_border_color;\n    struct nk_color group_border_color;\n    struct nk_color tooltip_border_color;\n    struct nk_style_item scaler;\n\n    float border;\n    float combo_border;\n    float contextual_border;\n    float menu_border;\n    float group_border;\n    float tooltip_border;\n    float popup_border;\n    float min_row_height_padding;\n\n    float rounding;\n    struct nk_vec2 spacing;\n    struct nk_vec2 scrollbar_size;\n    struct nk_vec2 min_size;\n\n    struct nk_vec2 padding;\n    struct nk_vec2 group_padding;\n    struct nk_vec2 popup_padding;\n    struct nk_vec2 combo_padding;\n    struct nk_vec2 contextual_padding;\n    struct nk_vec2 menu_padding;\n    struct nk_vec2 tooltip_padding;\n\n    enum nk_tooltip_pos tooltip_origin;\n    struct nk_vec2 tooltip_offset;\n};\n\nstruct nk_style {\n    const struct nk_user_font *font;\n    const struct nk_cursor *cursors[NK_CURSOR_COUNT];\n    const struct nk_cursor *cursor_active;\n    struct nk_cursor *cursor_last;\n    int cursor_visible;\n\n    struct nk_style_text text;\n    struct nk_style_button button;\n    struct nk_style_button contextual_button;\n    struct nk_style_button menu_button;\n    struct nk_style_toggle option;\n    struct nk_style_toggle checkbox;\n    struct nk_style_selectable selectable;\n    struct nk_style_slider slider;\n    struct nk_style_knob knob;\n    struct nk_style_progress progress;\n    struct nk_style_property property;\n    struct nk_style_edit edit;\n    struct nk_style_chart chart;\n    struct nk_style_scrollbar scrollh;\n    struct nk_style_scrollbar scrollv;\n    struct nk_style_tab tab;\n    struct nk_style_combo combo;\n    struct nk_style_window window;\n};\n\nNK_API struct nk_style_item nk_style_item_color(struct nk_color);\nNK_API struct nk_style_item nk_style_item_image(struct nk_image img);\nNK_API struct nk_style_item nk_style_item_nine_slice(struct nk_nine_slice slice);\nNK_API struct nk_style_item nk_style_item_hide(void);\n\n/*==============================================================\n *                          PANEL\n * =============================================================*/\n#ifndef NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS\n#define NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS 16\n#endif\n#ifndef NK_CHART_MAX_SLOT\n#define NK_CHART_MAX_SLOT 4\n#endif\n\nenum nk_panel_type {\n    NK_PANEL_NONE       = 0,\n    NK_PANEL_WINDOW     = NK_FLAG(0),\n    NK_PANEL_GROUP      = NK_FLAG(1),\n    NK_PANEL_POPUP      = NK_FLAG(2),\n    NK_PANEL_CONTEXTUAL = NK_FLAG(4),\n    NK_PANEL_COMBO      = NK_FLAG(5),\n    NK_PANEL_MENU       = NK_FLAG(6),\n    NK_PANEL_TOOLTIP    = NK_FLAG(7)\n};\nenum nk_panel_set {\n    NK_PANEL_SET_NONBLOCK = NK_PANEL_CONTEXTUAL|NK_PANEL_COMBO|NK_PANEL_MENU|NK_PANEL_TOOLTIP,\n    NK_PANEL_SET_POPUP = NK_PANEL_SET_NONBLOCK|NK_PANEL_POPUP,\n    NK_PANEL_SET_SUB = NK_PANEL_SET_POPUP|NK_PANEL_GROUP\n};\n\nstruct nk_chart_slot {\n    enum nk_chart_type type;\n    struct nk_color color;\n    struct nk_color highlight;\n    float min, max, range;\n    int count;\n    struct nk_vec2 last;\n    int index;\n    nk_bool show_markers;\n};\n\nstruct nk_chart {\n    int slot;\n    float x, y, w, h;\n    struct nk_chart_slot slots[NK_CHART_MAX_SLOT];\n};\n\nenum nk_panel_row_layout_type {\n    NK_LAYOUT_DYNAMIC_FIXED = 0,\n    NK_LAYOUT_DYNAMIC_ROW,\n    NK_LAYOUT_DYNAMIC_FREE,\n    NK_LAYOUT_DYNAMIC,\n    NK_LAYOUT_STATIC_FIXED,\n    NK_LAYOUT_STATIC_ROW,\n    NK_LAYOUT_STATIC_FREE,\n    NK_LAYOUT_STATIC,\n    NK_LAYOUT_TEMPLATE,\n    NK_LAYOUT_COUNT\n};\nstruct nk_row_layout {\n    enum nk_panel_row_layout_type type;\n    int index;\n    float height;\n    float min_height;\n    int columns;\n    const float *ratio;\n    float item_width;\n    float item_height;\n    float item_offset;\n    float filled;\n    struct nk_rect item;\n    int tree_depth;\n    float templates[NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS];\n};\n\nstruct nk_popup_buffer {\n    nk_size begin;\n    nk_size parent;\n    nk_size last;\n    nk_size end;\n    nk_bool active;\n};\n\nstruct nk_menu_state {\n    float x, y, w, h;\n    struct nk_scroll offset;\n};\n\nstruct nk_panel {\n    enum nk_panel_type type;\n    nk_flags flags;\n    struct nk_rect bounds;\n    nk_uint *offset_x;\n    nk_uint *offset_y;\n    float at_x, at_y, max_x;\n    float footer_height;\n    float header_height;\n    float border;\n    unsigned int has_scrolling;\n    struct nk_rect clip;\n    struct nk_menu_state menu;\n    struct nk_row_layout row;\n    struct nk_chart chart;\n    struct nk_command_buffer *buffer;\n    struct nk_panel *parent;\n};\n\n/*==============================================================\n *                          WINDOW\n * =============================================================*/\n#ifndef NK_WINDOW_MAX_NAME\n#define NK_WINDOW_MAX_NAME 64\n#endif\n\nstruct nk_table;\nenum nk_window_flags {\n    NK_WINDOW_PRIVATE       = NK_FLAG(11),\n    NK_WINDOW_DYNAMIC       = NK_WINDOW_PRIVATE,                  /**< special window type growing up in height while being filled to a certain maximum height */\n    NK_WINDOW_ROM           = NK_FLAG(12),                        /**< sets window widgets into a read only mode and does not allow input changes */\n    NK_WINDOW_NOT_INTERACTIVE = NK_WINDOW_ROM|NK_WINDOW_NO_INPUT, /**< prevents all interaction caused by input to either window or widgets inside */\n    NK_WINDOW_HIDDEN        = NK_FLAG(13),                        /**< Hides window and stops any window interaction and drawing */\n    NK_WINDOW_CLOSED        = NK_FLAG(14),                        /**< Directly closes and frees the window at the end of the frame */\n    NK_WINDOW_MINIMIZED     = NK_FLAG(15),                        /**< marks the window as minimized */\n    NK_WINDOW_REMOVE_ROM    = NK_FLAG(16)                         /**< Removes read only mode at the end of the window */\n};\n\nstruct nk_popup_state {\n    struct nk_window *win;\n    enum nk_panel_type type;\n    struct nk_popup_buffer buf;\n    nk_hash name;\n    nk_bool active;\n    unsigned combo_count;\n    unsigned con_count, con_old;\n    unsigned active_con;\n    struct nk_rect header;\n};\n\nstruct nk_edit_state {\n    nk_hash name;\n    unsigned int seq;\n    unsigned int old;\n    int active, prev;\n    int cursor;\n    int sel_start;\n    int sel_end;\n    struct nk_scroll scrollbar;\n    unsigned char mode;\n    unsigned char single_line;\n};\n\nstruct nk_property_state {\n    int active, prev;\n    char buffer[NK_MAX_NUMBER_BUFFER];\n    int length;\n    int cursor;\n    int select_start;\n    int select_end;\n    nk_hash name;\n    unsigned int seq;\n    unsigned int old;\n    int state;\n    int prev_state;\n    nk_hash prev_name;\n    char prev_buffer[NK_MAX_NUMBER_BUFFER];\n    int prev_length;\n};\n\nstruct nk_window {\n    unsigned int seq;\n    nk_hash name;\n    char name_string[NK_WINDOW_MAX_NAME];\n    nk_flags flags;\n\n    struct nk_rect bounds;\n    struct nk_scroll scrollbar;\n    struct nk_command_buffer buffer;\n    struct nk_panel *layout;\n    float scrollbar_hiding_timer;\n\n    /* persistent widget state */\n    struct nk_property_state property;\n    struct nk_popup_state popup;\n    struct nk_edit_state edit;\n    unsigned int scrolled;\n    nk_bool widgets_disabled;\n\n    struct nk_table *tables;\n    unsigned int table_count;\n\n    /* window list hooks */\n    struct nk_window *next;\n    struct nk_window *prev;\n    struct nk_window *parent;\n};\n\n/*==============================================================\n *                          STACK\n * =============================================================*/\n/**\n * \\page Stack\n * The style modifier stack can be used to temporarily change a\n * property inside `nk_style`. For example if you want a special\n * red button you can temporarily push the old button color onto a stack\n * draw the button with a red color and then you just pop the old color\n * back from the stack:\n *\n *     nk_style_push_style_item(ctx, &ctx->style.button.normal, nk_style_item_color(nk_rgb(255,0,0)));\n *     nk_style_push_style_item(ctx, &ctx->style.button.hover, nk_style_item_color(nk_rgb(255,0,0)));\n *     nk_style_push_style_item(ctx, &ctx->style.button.active, nk_style_item_color(nk_rgb(255,0,0)));\n *     nk_style_push_vec2(ctx, &cx->style.button.padding, nk_vec2(2,2));\n *\n *     nk_button(...);\n *\n *     nk_style_pop_style_item(ctx);\n *     nk_style_pop_style_item(ctx);\n *     nk_style_pop_style_item(ctx);\n *     nk_style_pop_vec2(ctx);\n *\n * Nuklear has a stack for style_items, float properties, vector properties,\n * flags, colors, fonts and for button_behavior. Each has it's own fixed size stack\n * which can be changed at compile time.\n */\n\n#ifndef NK_BUTTON_BEHAVIOR_STACK_SIZE\n#define NK_BUTTON_BEHAVIOR_STACK_SIZE 8\n#endif\n\n#ifndef NK_FONT_STACK_SIZE\n#define NK_FONT_STACK_SIZE 8\n#endif\n\n#ifndef NK_STYLE_ITEM_STACK_SIZE\n#define NK_STYLE_ITEM_STACK_SIZE 16\n#endif\n\n#ifndef NK_FLOAT_STACK_SIZE\n#define NK_FLOAT_STACK_SIZE 32\n#endif\n\n#ifndef NK_VECTOR_STACK_SIZE\n#define NK_VECTOR_STACK_SIZE 16\n#endif\n\n#ifndef NK_FLAGS_STACK_SIZE\n#define NK_FLAGS_STACK_SIZE 32\n#endif\n\n#ifndef NK_COLOR_STACK_SIZE\n#define NK_COLOR_STACK_SIZE 32\n#endif\n\n#define NK_CONFIGURATION_STACK_TYPE(prefix, name, type)\\\n    struct nk_config_stack_##name##_element {\\\n        prefix##_##type *address;\\\n        prefix##_##type old_value;\\\n    }\n#define NK_CONFIG_STACK(type,size)\\\n    struct nk_config_stack_##type {\\\n        int head;\\\n        struct nk_config_stack_##type##_element elements[size];\\\n    }\n\n#define nk_float float\nNK_CONFIGURATION_STACK_TYPE(struct nk, style_item, style_item);\nNK_CONFIGURATION_STACK_TYPE(nk ,float, float);\nNK_CONFIGURATION_STACK_TYPE(struct nk, vec2, vec2);\nNK_CONFIGURATION_STACK_TYPE(nk ,flags, flags);\nNK_CONFIGURATION_STACK_TYPE(struct nk, color, color);\nNK_CONFIGURATION_STACK_TYPE(const struct nk, user_font, user_font*);\nNK_CONFIGURATION_STACK_TYPE(enum nk, button_behavior, button_behavior);\n\nNK_CONFIG_STACK(style_item, NK_STYLE_ITEM_STACK_SIZE);\nNK_CONFIG_STACK(float, NK_FLOAT_STACK_SIZE);\nNK_CONFIG_STACK(vec2, NK_VECTOR_STACK_SIZE);\nNK_CONFIG_STACK(flags, NK_FLAGS_STACK_SIZE);\nNK_CONFIG_STACK(color, NK_COLOR_STACK_SIZE);\nNK_CONFIG_STACK(user_font, NK_FONT_STACK_SIZE);\nNK_CONFIG_STACK(button_behavior, NK_BUTTON_BEHAVIOR_STACK_SIZE);\n\nstruct nk_configuration_stacks {\n    struct nk_config_stack_style_item style_items;\n    struct nk_config_stack_float floats;\n    struct nk_config_stack_vec2 vectors;\n    struct nk_config_stack_flags flags;\n    struct nk_config_stack_color colors;\n    struct nk_config_stack_user_font fonts;\n    struct nk_config_stack_button_behavior button_behaviors;\n};\n\n/*==============================================================\n *                          CONTEXT\n * =============================================================*/\n#define NK_VALUE_PAGE_CAPACITY \\\n    (((NK_MAX(sizeof(struct nk_window),sizeof(struct nk_panel)) / sizeof(nk_uint))) / 2)\n\nstruct nk_table {\n    unsigned int seq;\n    unsigned int size;\n    nk_hash keys[NK_VALUE_PAGE_CAPACITY];\n    nk_uint values[NK_VALUE_PAGE_CAPACITY];\n    struct nk_table *next, *prev;\n};\n\nunion nk_page_data {\n    struct nk_table tbl;\n    struct nk_panel pan;\n    struct nk_window win;\n};\n\nstruct nk_page_element {\n    union nk_page_data data;\n    struct nk_page_element *next;\n    struct nk_page_element *prev;\n};\n\nstruct nk_page {\n    unsigned int size;\n    struct nk_page *next;\n    struct nk_page_element win[1];\n};\n\nstruct nk_pool {\n    struct nk_allocator alloc;\n    enum nk_allocation_type type;\n    unsigned int page_count;\n    struct nk_page *pages;\n    struct nk_page_element *freelist;\n    unsigned capacity;\n    nk_size size;\n    nk_size cap;\n};\n\nstruct nk_context {\n/* public: can be accessed freely */\n    struct nk_input input;\n    struct nk_style style;\n    struct nk_buffer memory;\n    struct nk_clipboard clip;\n    nk_flags last_widget_state;\n    enum nk_button_behavior button_behavior;\n    struct nk_configuration_stacks stacks;\n    float delta_time_seconds;\n\n/* private:\n    should only be accessed if you\n    know what you are doing */\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n    struct nk_draw_list draw_list;\n#endif\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    nk_handle userdata;\n#endif\n    /** text editor objects are quite big because of an internal\n     * undo/redo stack. Therefore it does not make sense to have one for\n     * each window for temporary use cases, so I only provide *one* instance\n     * for all windows. This works because the content is cleared anyway */\n    struct nk_text_edit text_edit;\n    /** draw buffer used for overlay drawing operation like cursor */\n    struct nk_command_buffer overlay;\n\n    /** windows */\n    int build;\n    int use_pool;\n    struct nk_pool pool;\n    struct nk_window *begin;\n    struct nk_window *end;\n    struct nk_window *active;\n    struct nk_window *current;\n    struct nk_page_element *freelist;\n    unsigned int count;\n    unsigned int seq;\n};\n\n/* ==============================================================\n *                          MATH\n * =============================================================== */\n#define NK_PI 3.141592654f\n#define NK_PI_HALF 1.570796326f\n#define NK_UTF_INVALID 0xFFFD\n#define NK_MAX_FLOAT_PRECISION 2\n\n#define NK_UNUSED(x) ((void)(x))\n#define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x)))\n#define NK_LEN(a) (sizeof(a)/sizeof(a)[0])\n#define NK_ABS(a) (((a) < 0) ? -(a) : (a))\n#define NK_BETWEEN(x, a, b) ((a) <= (x) && (x) < (b))\n#define NK_INBOX(px, py, x, y, w, h)\\\n    (NK_BETWEEN(px,x,x+w) && NK_BETWEEN(py,y,y+h))\n#define NK_INTERSECT(x0, y0, w0, h0, x1, y1, w1, h1) \\\n    ((x1 < (x0 + w0)) && (x0 < (x1 + w1)) && \\\n    (y1 < (y0 + h0)) && (y0 < (y1 + h1)))\n#define NK_CONTAINS(x, y, w, h, bx, by, bw, bh)\\\n    (NK_INBOX(x,y, bx, by, bw, bh) && NK_INBOX(x+w,y+h, bx, by, bw, bh))\n\n#define nk_vec2_sub(a, b) nk_vec2((a).x - (b).x, (a).y - (b).y)\n#define nk_vec2_add(a, b) nk_vec2((a).x + (b).x, (a).y + (b).y)\n#define nk_vec2_len_sqr(a) ((a).x*(a).x+(a).y*(a).y)\n#define nk_vec2_muls(a, t) nk_vec2((a).x * (t), (a).y * (t))\n\n#define nk_ptr_add(t, p, i) ((t*)((void*)((nk_byte*)(p) + (i))))\n#define nk_ptr_add_const(t, p, i) ((const t*)((const void*)((const nk_byte*)(p) + (i))))\n#define nk_zero_struct(s) nk_zero(&s, sizeof(s))\n\n/* ==============================================================\n *                          ALIGNMENT\n * =============================================================== */\n/* Pointer to Integer type conversion for pointer alignment */\n#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC*/\n# define NK_UINT_TO_PTR(x) ((void*)(__PTRDIFF_TYPE__)(x))\n# define NK_PTR_TO_UINT(x) ((nk_size)(__PTRDIFF_TYPE__)(x))\n#elif !defined(__GNUC__) /* works for compilers other than LLVM */\n# define NK_UINT_TO_PTR(x) ((void*)&((char*)0)[x])\n# define NK_PTR_TO_UINT(x) ((nk_size)(((char*)x)-(char*)0))\n#elif defined(NK_USE_FIXED_TYPES) /* used if we have <stdint.h> */\n# define NK_UINT_TO_PTR(x) ((void*)(uintptr_t)(x))\n# define NK_PTR_TO_UINT(x) ((uintptr_t)(x))\n#else /* generates warning but works */\n# define NK_UINT_TO_PTR(x) ((void*)(x))\n# define NK_PTR_TO_UINT(x) ((nk_size)(x))\n#endif\n\n#define NK_ALIGN_PTR(x, mask)\\\n    (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x) + (mask-1)) & ~(mask-1))))\n#define NK_ALIGN_PTR_BACK(x, mask)\\\n    (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x)) & ~(mask-1))))\n\n#if ((defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)) && !defined(EMSCRIPTEN)\n#define NK_OFFSETOF(st,m) (__builtin_offsetof(st,m))\n#else\n#define NK_OFFSETOF(st,m) ((nk_ptr)&(((st*)0)->m))\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#ifdef __cplusplus\ntemplate<typename T> struct nk_alignof;\ntemplate<typename T, int size_diff> struct nk_helper{enum {value = size_diff};};\ntemplate<typename T> struct nk_helper<T,0>{enum {value = nk_alignof<T>::value};};\ntemplate<typename T> struct nk_alignof{struct Big {T x; char c;}; enum {\n    diff = sizeof(Big) - sizeof(T), value = nk_helper<Big, diff>::value};};\n#define NK_ALIGNOF(t) (nk_alignof<t>::value)\n#else\n#define NK_ALIGNOF(t) NK_OFFSETOF(struct {char c; t _h;}, _h)\n#endif\n\n#define NK_CONTAINER_OF(ptr,type,member)\\\n    (type*)((void*)((char*)(1 ? (ptr): &((type*)0)->member) - NK_OFFSETOF(type, member)))\n\n\n\n#endif /* NK_NUKLEAR_H_ */\n\n#ifdef NK_IMPLEMENTATION\n\n#ifndef NK_INTERNAL_H\n#define NK_INTERNAL_H\n\n#ifndef NK_POOL_DEFAULT_CAPACITY\n#define NK_POOL_DEFAULT_CAPACITY 16\n#endif\n\n#ifndef NK_DEFAULT_COMMAND_BUFFER_SIZE\n#define NK_DEFAULT_COMMAND_BUFFER_SIZE (4*1024)\n#endif\n\n#ifndef NK_BUFFER_DEFAULT_INITIAL_SIZE\n#define NK_BUFFER_DEFAULT_INITIAL_SIZE (4*1024)\n#endif\n\n/* standard library headers */\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\n#include <stdlib.h> /* malloc, free */\n#endif\n#ifdef NK_INCLUDE_STANDARD_IO\n#include <stdio.h> /* fopen, fclose,... */\n#endif\n#ifdef NK_INCLUDE_STANDARD_VARARGS\n#include <stdarg.h> /* valist, va_start, va_end, ... */\n#endif\n#ifndef NK_ASSERT\n#include <assert.h>\n#define NK_ASSERT(expr) assert(expr)\n#endif\n\n#define NK_DEFAULT (-1)\n\n#ifndef NK_VSNPRINTF\n/* If your compiler does support `vsnprintf` I would highly recommend\n * defining this to vsnprintf instead since `vsprintf` is basically\n * unbelievable unsafe and should *NEVER* be used. But I have to support\n * it since C89 only provides this unsafe version. */\n  #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) ||\\\n      (defined(__cplusplus) && (__cplusplus >= 201103L)) || \\\n      (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) ||\\\n      (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) ||\\\n       defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE)\n      #define NK_VSNPRINTF(s,n,f,a) vsnprintf(s,n,f,a)\n  #else\n    #define NK_VSNPRINTF(s,n,f,a) vsprintf(s,f,a)\n  #endif\n#endif\n\n#define NK_SCHAR_MIN (-127)\n#define NK_SCHAR_MAX 127\n#define NK_UCHAR_MIN 0\n#define NK_UCHAR_MAX 256\n#define NK_SSHORT_MIN (-32767)\n#define NK_SSHORT_MAX 32767\n#define NK_USHORT_MIN 0\n#define NK_USHORT_MAX 65535\n#define NK_SINT_MIN (-2147483647)\n#define NK_SINT_MAX 2147483647\n#define NK_UINT_MIN 0\n#define NK_UINT_MAX 4294967295u\n\n/* Make sure correct type size:\n * This will fire with a negative subscript error if the type sizes\n * are set incorrectly by the compiler, and compile out if not */\nNK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*));\nNK_STATIC_ASSERT(sizeof(nk_ptr) == sizeof(void*));\nNK_STATIC_ASSERT(sizeof(nk_flags) >= 4);\nNK_STATIC_ASSERT(sizeof(nk_rune) >= 4);\nNK_STATIC_ASSERT(sizeof(nk_ushort) == 2);\nNK_STATIC_ASSERT(sizeof(nk_short) == 2);\nNK_STATIC_ASSERT(sizeof(nk_uint) == 4);\nNK_STATIC_ASSERT(sizeof(nk_int) == 4);\nNK_STATIC_ASSERT(sizeof(nk_byte) == 1);\nNK_STATIC_ASSERT(sizeof(nk_bool) <= sizeof(int));\n\nNK_GLOBAL const struct nk_rect nk_null_rect = {-8192.0f, -8192.0f, 16384, 16384};\n#define NK_FLOAT_PRECISION 0.00000000000001\n\nNK_GLOBAL const struct nk_color nk_red = {255,0,0,255};\nNK_GLOBAL const struct nk_color nk_green = {0,255,0,255};\nNK_GLOBAL const struct nk_color nk_blue = {0,0,255,255};\nNK_GLOBAL const struct nk_color nk_white = {255,255,255,255};\nNK_GLOBAL const struct nk_color nk_black = {0,0,0,255};\nNK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255};\n\n/* widget */\n#define nk_widget_state_reset(s)\\\n    if ((*(s)) & NK_WIDGET_STATE_MODIFIED)\\\n        (*(s)) = NK_WIDGET_STATE_INACTIVE|NK_WIDGET_STATE_MODIFIED;\\\n    else (*(s)) = NK_WIDGET_STATE_INACTIVE;\n\n/* math */\n#ifndef NK_INV_SQRT\n#define NK_INV_SQRT nk_inv_sqrt\n#define NK_INV_SQRT_NEEDED\nNK_LIB float nk_inv_sqrt(float n);\n#endif\n#ifndef NK_SIN\n#define NK_SIN nk_sin\n#define NK_SIN_NEEDED\nNK_LIB float nk_sin(float x);\n#endif\n#ifndef NK_COS\n#define NK_COS nk_cos\n#define NK_COS_NEEDED\nNK_LIB float nk_cos(float x);\n#endif\n#ifndef NK_ATAN\n#define NK_ATAN nk_atan\n#define NK_ATAN_NEEDED\nNK_LIB float nk_atan(float x);\n#endif\n#ifndef NK_ATAN2\n#define NK_ATAN2 nk_atan2\n#define NK_ATAN2_NEEDED\nNK_LIB float nk_atan2(float y, float x);\n#endif\nNK_LIB nk_uint nk_round_up_pow2(nk_uint v);\nNK_LIB struct nk_rect nk_shrink_rect(struct nk_rect r, float amount);\nNK_LIB struct nk_rect nk_pad_rect(struct nk_rect r, struct nk_vec2 pad);\nNK_LIB void nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0, float x1, float y1);\nNK_LIB int nk_ifloorf(float x);\nNK_LIB int nk_iceilf(float x);\nNK_LIB float nk_roundf(float x);\n\n/* util */\nenum {NK_DO_NOT_STOP_ON_NEW_LINE, NK_STOP_ON_NEW_LINE};\nNK_LIB nk_bool nk_is_lower(int c);\nNK_LIB nk_bool nk_is_upper(int c);\nNK_LIB int nk_to_upper(int c);\nNK_LIB int nk_to_lower(int c);\n\n#ifndef NK_MEMCPY\n#define NK_MEMCPY nk_memcopy\n#define NK_MEMCPY_NEEDED\nNK_LIB void* nk_memcopy(void *dst, const void *src, nk_size n);\n#endif\n#ifndef NK_MEMSET\n#define NK_MEMSET nk_memset\n#define NK_MEMSET_NEEDED\nNK_LIB void nk_memset(void *ptr, int c0, nk_size size);\n#endif\nNK_LIB void nk_zero(void *ptr, nk_size size);\nNK_LIB char *nk_itoa(char *s, long n);\nNK_LIB int nk_string_float_limit(char *string, int prec);\n#ifndef NK_DTOA\n#define NK_DTOA nk_dtoa\n#define NK_DTOA_NEEDED\nNK_LIB char *nk_dtoa(char *s, double n);\n#endif\nNK_LIB int nk_text_clamp(const struct nk_user_font *font, const char *text, int text_len, float space, int *glyphs, float *text_width, nk_rune *sep_list, int sep_count);\nNK_LIB struct nk_vec2 nk_text_calculate_text_bounds(const struct nk_user_font *font, const char *begin, int byte_len, float row_height, const char **remaining, struct nk_vec2 *out_offset, int *glyphs, int op);\n#ifdef NK_INCLUDE_STANDARD_VARARGS\nNK_LIB int nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args);\n#endif\n#ifdef NK_INCLUDE_STANDARD_IO\nNK_LIB char *nk_file_load(const char* path, nk_size* siz, const struct nk_allocator *alloc);\n#endif\n\n/* math helpers that are only used by nk_dtoa */\n#ifdef NK_DTOA_NEEDED\nNK_LIB double nk_pow(double x, int n);\nNK_LIB int nk_ifloord(double x);\nNK_LIB int nk_log10(double n);\n#endif\n\n/* buffer */\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_LIB void* nk_malloc(nk_handle unused, void *old,nk_size size);\nNK_LIB void nk_mfree(nk_handle unused, void *ptr);\n#endif\nNK_LIB void* nk_buffer_align(void *unaligned, nk_size align, nk_size *alignment, enum nk_buffer_allocation_type type);\nNK_LIB void* nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type, nk_size size, nk_size align);\nNK_LIB void* nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size);\n\n/* draw */\nNK_LIB void nk_command_buffer_init(struct nk_command_buffer *cb, struct nk_buffer *b, enum nk_command_clipping clip);\nNK_LIB void nk_command_buffer_reset(struct nk_command_buffer *b);\nNK_LIB void* nk_command_buffer_push(struct nk_command_buffer* b, enum nk_command_type t, nk_size size);\nNK_LIB void nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type, struct nk_rect content, struct nk_color background, struct nk_color foreground, float border_width, const struct nk_user_font *font);\n\n/* buffering */\nNK_LIB void nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *b);\nNK_LIB void nk_start(struct nk_context *ctx, struct nk_window *win);\nNK_LIB void nk_start_popup(struct nk_context *ctx, struct nk_window *win);\nNK_LIB void nk_finish_popup(struct nk_context *ctx, struct nk_window*);\nNK_LIB void nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *b);\nNK_LIB void nk_finish(struct nk_context *ctx, struct nk_window *w);\nNK_LIB void nk_build(struct nk_context *ctx);\n\n/* text editor */\nNK_LIB void nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type, nk_plugin_filter filter);\nNK_LIB void nk_textedit_click(struct nk_text_edit *state, float x, float y, const struct nk_user_font *font, float row_height);\nNK_LIB void nk_textedit_drag(struct nk_text_edit *state, float x, float y, const struct nk_user_font *font, float row_height);\nNK_LIB void nk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod, const struct nk_user_font *font, float row_height);\n\n/* window */\nenum nk_window_insert_location {\n    NK_INSERT_BACK, /* inserts window into the back of list (front of screen) */\n    NK_INSERT_FRONT /* inserts window into the front of list (back of screen) */\n};\nNK_LIB void *nk_create_window(struct nk_context *ctx);\nNK_LIB void nk_remove_window(struct nk_context*, struct nk_window*);\nNK_LIB void nk_free_window(struct nk_context *ctx, struct nk_window *win);\nNK_LIB struct nk_window *nk_find_window(const struct nk_context *ctx, nk_hash hash, const char *name);\nNK_LIB void nk_insert_window(struct nk_context *ctx, struct nk_window *win, enum nk_window_insert_location loc);\n\n/* pool */\nNK_LIB void nk_pool_init(struct nk_pool *pool, const struct nk_allocator *alloc, unsigned int capacity);\nNK_LIB void nk_pool_free(struct nk_pool *pool);\nNK_LIB void nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size);\nNK_LIB struct nk_page_element *nk_pool_alloc(struct nk_pool *pool);\n\n/* page-element */\nNK_LIB struct nk_page_element* nk_create_page_element(struct nk_context *ctx);\nNK_LIB void nk_link_page_element_into_freelist(struct nk_context *ctx, struct nk_page_element *elem);\nNK_LIB void nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem);\n\n/* table */\nNK_LIB struct nk_table* nk_create_table(struct nk_context *ctx);\nNK_LIB void nk_remove_table(struct nk_window *win, struct nk_table *tbl);\nNK_LIB void nk_free_table(struct nk_context *ctx, struct nk_table *tbl);\nNK_LIB void nk_push_table(struct nk_window *win, struct nk_table *tbl);\nNK_LIB nk_uint *nk_add_value(struct nk_context *ctx, struct nk_window *win, nk_hash name, nk_uint value);\nNK_LIB nk_uint *nk_find_value(const struct nk_window *win, nk_hash name);\n\n/* panel */\nNK_LIB void *nk_create_panel(struct nk_context *ctx);\nNK_LIB void nk_free_panel(struct nk_context*, struct nk_panel *pan);\nNK_LIB nk_bool nk_panel_has_header(nk_flags flags, const char *title);\nNK_LIB struct nk_vec2 nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type);\nNK_LIB float nk_panel_get_border(const struct nk_style *style, nk_flags flags, enum nk_panel_type type);\nNK_LIB struct nk_color nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type);\nNK_LIB nk_bool nk_panel_is_sub(enum nk_panel_type type);\nNK_LIB nk_bool nk_panel_is_nonblock(enum nk_panel_type type);\nNK_LIB nk_bool nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type);\nNK_LIB void nk_panel_end(struct nk_context *ctx);\n\n/* layout */\nNK_LIB float nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type, float total_space, int columns);\nNK_LIB void nk_panel_layout(const struct nk_context *ctx, struct nk_window *win, float height, int cols);\nNK_LIB void nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt, float height, int cols, int width);\nNK_LIB void nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win);\nNK_LIB void nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx, struct nk_window *win, int modify);\nNK_LIB void nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx);\nNK_LIB void nk_layout_peek(struct nk_rect *bounds, const struct nk_context *ctx);\n\n/* popup */\nNK_LIB nk_bool nk_nonblock_begin(struct nk_context *ctx, nk_flags flags, struct nk_rect body, struct nk_rect header, enum nk_panel_type panel_type);\n\n/* text */\nstruct nk_text {\n    struct nk_vec2 padding;\n    struct nk_color background;\n    struct nk_color text;\n};\nNK_LIB void nk_widget_text(struct nk_command_buffer *o, struct nk_rect b, const char *string, int len, const struct nk_text *t, nk_flags a, const struct nk_user_font *f);\nNK_LIB void nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b, const char *string, int len, const struct nk_text *t, const struct nk_user_font *f);\n\n/* button */\nNK_LIB nk_bool nk_button_behavior(nk_flags *state, struct nk_rect r, const struct nk_input *i, enum nk_button_behavior behavior);\nNK_LIB const struct nk_style_item* nk_draw_button(struct nk_command_buffer *out, const struct nk_rect *bounds, nk_flags state, const struct nk_style_button *style);\nNK_LIB nk_bool nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, const struct nk_style_button *style, const struct nk_input *in, enum nk_button_behavior behavior, struct nk_rect *content);\nNK_LIB void nk_draw_button_text(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, const char *txt, int len, nk_flags text_alignment, const struct nk_user_font *font);\nNK_LIB nk_bool nk_do_button_text(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *string, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_input *in, const struct nk_user_font *font);\nNK_LIB void nk_draw_button_symbol(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, enum nk_symbol_type type, const struct nk_user_font *font);\nNK_LIB nk_bool nk_do_button_symbol(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, enum nk_symbol_type symbol, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_input *in, const struct nk_user_font *font);\nNK_LIB void nk_draw_button_image(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, const struct nk_image *img);\nNK_LIB nk_bool nk_do_button_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, struct nk_image img, enum nk_button_behavior b, const struct nk_style_button *style, const struct nk_input *in);\nNK_LIB void nk_draw_button_text_symbol(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *label, const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style, const char *str, int len, enum nk_symbol_type type, const struct nk_user_font *font);\nNK_LIB nk_bool nk_do_button_text_symbol(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, enum nk_symbol_type symbol, const char *str, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_user_font *font, const struct nk_input *in);\nNK_LIB void nk_draw_button_text_image(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *label, const struct nk_rect *image, nk_flags state, const struct nk_style_button *style, const char *str, int len, const struct nk_user_font *font, const struct nk_image *img);\nNK_LIB nk_bool nk_do_button_text_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, struct nk_image img, const char* str, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_user_font *font, const struct nk_input *in);\n\n/* toggle */\nenum nk_toggle_type {\n    NK_TOGGLE_CHECK,\n    NK_TOGGLE_OPTION\n};\nNK_LIB nk_bool nk_toggle_behavior(const struct nk_input *in, struct nk_rect select, nk_flags *state, nk_bool active);\nNK_LIB void nk_draw_checkbox(struct nk_command_buffer *out, nk_flags state, const struct nk_style_toggle *style, nk_bool active, const struct nk_rect *label, const struct nk_rect *selector, const struct nk_rect *cursors, const char *string, int len, const struct nk_user_font *font, nk_flags text_alignment);\nNK_LIB void nk_draw_option(struct nk_command_buffer *out, nk_flags state, const struct nk_style_toggle *style, nk_bool active, const struct nk_rect *label, const struct nk_rect *selector, const struct nk_rect *cursors, const char *string, int len, const struct nk_user_font *font, nk_flags text_alignment);\nNK_LIB nk_bool nk_do_toggle(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, nk_bool *active, const char *str, int len, enum nk_toggle_type type, const struct nk_style_toggle *style, const struct nk_input *in, const struct nk_user_font *font, nk_flags widget_alignment, nk_flags text_alignment);\n\n/* progress */\nNK_LIB nk_size nk_progress_behavior(nk_flags *state, struct nk_input *in, struct nk_rect r, struct nk_rect cursor, nk_size max, nk_size value, nk_bool modifiable);\nNK_LIB void nk_draw_progress(struct nk_command_buffer *out, nk_flags state, const struct nk_style_progress *style, const struct nk_rect *bounds, const struct nk_rect *scursor, nk_size value, nk_size max);\nNK_LIB nk_size nk_do_progress(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, nk_size value, nk_size max, nk_bool modifiable, const struct nk_style_progress *style, struct nk_input *in);\n\n/* slider */\nNK_LIB float nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor, struct nk_rect *visual_cursor, struct nk_input *in, struct nk_rect bounds, float slider_min, float slider_max, float slider_value, float slider_step, float slider_steps);\nNK_LIB void nk_draw_slider(struct nk_command_buffer *out, nk_flags state, const struct nk_style_slider *style, const struct nk_rect *bounds, const struct nk_rect *visual_cursor, float min, float value, float max);\nNK_LIB float nk_do_slider(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, float min, float val, float max, float step, const struct nk_style_slider *style, struct nk_input *in, const struct nk_user_font *font);\n\n/* scrollbar */\nNK_LIB float nk_scrollbar_behavior(nk_flags *state, struct nk_input *in, int has_scrolling, const struct nk_rect *scroll, const struct nk_rect *cursor, const struct nk_rect *empty0, const struct nk_rect *empty1, float scroll_offset, float target, float scroll_step, enum nk_orientation o);\nNK_LIB void nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state, const struct nk_style_scrollbar *style, const struct nk_rect *bounds, const struct nk_rect *scroll);\nNK_LIB float nk_do_scrollbarv(nk_flags *state, struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, float offset, float target, float step, float button_pixel_inc, const struct nk_style_scrollbar *style, struct nk_input *in, const struct nk_user_font *font);\nNK_LIB float nk_do_scrollbarh(nk_flags *state, struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, float offset, float target, float step, float button_pixel_inc, const struct nk_style_scrollbar *style, struct nk_input *in, const struct nk_user_font *font);\n\n/* selectable */\nNK_LIB void nk_draw_selectable(struct nk_command_buffer *out, nk_flags state, const struct nk_style_selectable *style, nk_bool active, const struct nk_rect *bounds, const struct nk_rect *icon, const struct nk_image *img, enum nk_symbol_type sym, const char *string, int len, nk_flags align, const struct nk_user_font *font);\nNK_LIB nk_bool nk_do_selectable(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, const struct nk_style_selectable *style, const struct nk_input *in, const struct nk_user_font *font);\nNK_LIB nk_bool nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, const struct nk_image *img, const struct nk_style_selectable *style, const struct nk_input *in, const struct nk_user_font *font);\n\n/* edit */\nNK_LIB void nk_edit_draw_text(struct nk_command_buffer *out, const struct nk_style_edit *style, float pos_x, float pos_y, float x_offset, const char *text, int byte_len, float row_height, const struct nk_user_font *font, struct nk_color background, struct nk_color foreground, nk_bool is_selected);\nNK_LIB nk_flags nk_do_edit(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter, struct nk_text_edit *edit, const struct nk_style_edit *style, struct nk_input *in, const struct nk_user_font *font);\n\n/* color-picker */\nNK_LIB nk_bool nk_color_picker_behavior(nk_flags *state, const struct nk_rect *bounds, const struct nk_rect *matrix, const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, struct nk_colorf *color, const struct nk_input *in);\nNK_LIB void nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix, const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, struct nk_colorf col);\nNK_LIB nk_bool nk_do_color_picker(nk_flags *state, struct nk_command_buffer *out, struct nk_colorf *col, enum nk_color_format fmt, struct nk_rect bounds, struct nk_vec2 padding, const struct nk_input *in, const struct nk_user_font *font);\n\n/* property */\nenum nk_property_status {\n    NK_PROPERTY_DEFAULT,\n    NK_PROPERTY_EDIT,\n    NK_PROPERTY_DRAG\n};\nenum nk_property_filter {\n    NK_FILTER_INT,\n    NK_FILTER_FLOAT\n};\nenum nk_property_kind {\n    NK_PROPERTY_INT,\n    NK_PROPERTY_FLOAT,\n    NK_PROPERTY_DOUBLE\n};\nunion nk_property {\n    int i;\n    float f;\n    double d;\n};\nstruct nk_property_variant {\n    enum nk_property_kind kind;\n    union nk_property value;\n    union nk_property min_value;\n    union nk_property max_value;\n    union nk_property step;\n};\nNK_LIB struct nk_property_variant nk_property_variant_int(int value, int min_value, int max_value, int step);\nNK_LIB struct nk_property_variant nk_property_variant_float(float value, float min_value, float max_value, float step);\nNK_LIB struct nk_property_variant nk_property_variant_double(double value, double min_value, double max_value, double step);\n\nNK_LIB void nk_drag_behavior(nk_flags *state, const struct nk_input *in, struct nk_rect drag, struct nk_property_variant *variant, float inc_per_pixel);\nNK_LIB void nk_property_behavior(nk_flags *ws, const struct nk_input *in, struct nk_rect property,  struct nk_rect label, struct nk_rect edit, struct nk_rect empty, int *state, struct nk_property_variant *variant, float inc_per_pixel);\nNK_LIB void nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style, const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state, const char *name, int len, const struct nk_user_font *font);\nNK_LIB void nk_do_property(nk_flags *ws, struct nk_command_buffer *out, struct nk_rect property, const char *name, struct nk_property_variant *variant, float inc_per_pixel, char *buffer, int *len, int *state, int *cursor, int *select_begin, int *select_end, const struct nk_style_property *style, enum nk_property_filter filter, struct nk_input *in, const struct nk_user_font *font, struct nk_text_edit *text_edit, enum nk_button_behavior behavior);\nNK_LIB void nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant, float inc_per_pixel, const enum nk_property_filter filter);\n\n#ifdef NK_INCLUDE_FONT_BAKING\n\n/**\n * @def NK_NO_STB_RECT_PACK_IMPLEMENTATION\n *\n * When defined, will avoid enabling STB_RECT_PACK_IMPLEMENTATION for when stb_rect_pack.h is already implemented elsewhere.\n */\n#ifndef NK_NO_STB_RECT_PACK_IMPLEMENTATION\n#define STB_RECT_PACK_IMPLEMENTATION\n#endif /* NK_NO_STB_RECT_PACK_IMPLEMENTATION */\n\n/**\n * @def NK_NO_STB_TRUETYPE_IMPLEMENTATION\n *\n * When defined, will avoid enabling STB_TRUETYPE_IMPLEMENTATION for when stb_truetype.h is already implemented elsewhere.\n */\n#ifndef NK_NO_STB_TRUETYPE_IMPLEMENTATION\n#define STB_TRUETYPE_IMPLEMENTATION\n#endif /* NK_NO_STB_TRUETYPE_IMPLEMENTATION */\n\n/* Allow consumer to define own STBTT_malloc/STBTT_free, and use the font atlas' allocator otherwise */\n#ifndef STBTT_malloc\nstatic void*\nnk_stbtt_malloc(nk_size size, void *user_data) {\n    struct nk_allocator *alloc = (struct nk_allocator *) user_data;\n    return alloc->alloc(alloc->userdata, 0, size);\n}\n\nstatic void\nnk_stbtt_free(void *ptr, void *user_data) {\n    struct nk_allocator *alloc = (struct nk_allocator *) user_data;\n    alloc->free(alloc->userdata, ptr);\n}\n\n#define STBTT_malloc(x,u)  nk_stbtt_malloc(x,u)\n#define STBTT_free(x,u)    nk_stbtt_free(x,u)\n\n#endif /* STBTT_malloc */\n\n#endif /* NK_INCLUDE_FONT_BAKING */\n\n#endif\n\n\n\n\n/* ===============================================================\n *\n *                              MATH\n *\n * ===============================================================*/\n/*/// ### Math\n///  Since nuklear is supposed to work on all systems providing floating point\n///  math without any dependencies I also had to implement my own math functions\n///  for sqrt, sin and cos. Since the actual highly accurate implementations for\n///  the standard library functions are quite complex and I do not need high\n///  precision for my use cases I use approximations.\n///\n///  Sqrt\n///  ----\n///  For square root nuklear uses the famous fast inverse square root:\n///  https://en.wikipedia.org/wiki/Fast_inverse_square_root with\n///  slightly tweaked magic constant. While on today's hardware it is\n///  probably not faster it is still fast and accurate enough for\n///  nuklear's use cases. IMPORTANT: this requires float format IEEE 754\n///\n///  Sine/Cosine\n///  -----------\n///  All constants inside both function are generated Remez's minimax\n///  approximations for value range 0...2*PI. The reason why I decided to\n///  approximate exactly that range is that nuklear only needs sine and\n///  cosine to generate circles which only requires that exact range.\n///  In addition I used Remez instead of Taylor for additional precision:\n///  www.lolengine.net/blog/2011/12/21/better-function-approximations.\n///\n///  The tool I used to generate constants for both sine and cosine\n///  (it can actually approximate a lot more functions) can be\n///  found here: www.lolengine.net/wiki/oss/lolremez\n*/\n#ifdef NK_INV_SQRT_NEEDED\nNK_LIB float\nnk_inv_sqrt(float n)\n{\n    float x2;\n    const float threehalfs = 1.5f;\n    union {nk_uint i; float f;} conv = {0};\n    conv.f = n;\n    x2 = n * 0.5f;\n    conv.i = 0x5f375A84 - (conv.i >> 1);\n    conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f));\n    return conv.f;\n}\n#endif\n#ifdef NK_SIN_NEEDED\nNK_LIB float\nnk_sin(float x)\n{\n    NK_STORAGE const float a0 = +1.91059300966915117e-31f;\n    NK_STORAGE const float a1 = +1.00086760103908896f;\n    NK_STORAGE const float a2 = -1.21276126894734565e-2f;\n    NK_STORAGE const float a3 = -1.38078780785773762e-1f;\n    NK_STORAGE const float a4 = -2.67353392911981221e-2f;\n    NK_STORAGE const float a5 = +2.08026600266304389e-2f;\n    NK_STORAGE const float a6 = -3.03996055049204407e-3f;\n    NK_STORAGE const float a7 = +1.38235642404333740e-4f;\n    return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7))))));\n}\n#endif\n#ifdef NK_COS_NEEDED\nNK_LIB float\nnk_cos(float x)\n{\n    /* New implementation. Also generated using lolremez. */\n    /* Old version significantly deviated from expected results. */\n    NK_STORAGE const float a0 = 9.9995999154986614e-1f;\n    NK_STORAGE const float a1 = 1.2548995793001028e-3f;\n    NK_STORAGE const float a2 = -5.0648546280678015e-1f;\n    NK_STORAGE const float a3 = 1.2942246466519995e-2f;\n    NK_STORAGE const float a4 = 2.8668384702547972e-2f;\n    NK_STORAGE const float a5 = 7.3726485210586547e-3f;\n    NK_STORAGE const float a6 = -3.8510875386947414e-3f;\n    NK_STORAGE const float a7 = 4.7196604604366623e-4f;\n    NK_STORAGE const float a8 = -1.8776444013090451e-5f;\n    return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*(a7 + x*a8)))))));\n}\n#endif\n#ifdef NK_ATAN_NEEDED\nNK_LIB float\nnk_atan(float x)\n{\n    /* ./lolremez --progress --float -d 9 -r \"0:pi*2\" \"atan(x)\" */\n    float u = -1.0989005e-05f;\n    NK_ASSERT(x >= 0.0f && \"TODO support negative floats\");\n    u = u * x + 0.00034117949f;\n    u = u * x + -0.0044932296f;\n    u = u * x + 0.032596264f;\n    u = u * x + -0.14088021f;\n    u = u * x + 0.36040401f;\n    u = u * x + -0.47017866f;\n    u = u * x + 0.00050198776f;\n    u = u * x + 1.0077682f;\n    u = u * x + -0.0004765437f;\n    return u;\n}\n#endif\n#ifdef NK_ATAN2_NEEDED\nNK_LIB float\nnk_atan2(float y, float x)\n{\n    float ax = NK_ABS(x),\n          ay = NK_ABS(y);\n    /* 0 = +y +x    1 = -y +x\n       2 = +y -x    3 = -y -x */\n    nk_uint signs = (y < 0) | ((x < 0) << 1);\n\n    float a;\n    if(y == 0.0 && x == 0.0) return 0.0f;\n    a = (ay > ax)\n        ? NK_PI_HALF - NK_ATAN(ax / ay)\n        : NK_ATAN(ay / ax);\n\n    switch(signs){\n        case 0: return a;\n        case 1: return -a;\n        case 2: return -a + NK_PI;\n        case 3: return a - NK_PI;\n    }\n    return 0.0f; /* prevents warning */\n}\n#endif\nNK_LIB nk_uint\nnk_round_up_pow2(nk_uint v)\n{\n    v--;\n    v |= v >> 1;\n    v |= v >> 2;\n    v |= v >> 4;\n    v |= v >> 8;\n    v |= v >> 16;\n    v++;\n    return v;\n}\n#ifdef NK_DTOA_NEEDED\nNK_LIB double\nnk_pow(double x, int n)\n{\n    /*  check the sign of n */\n    double r = 1;\n    int plus = n >= 0;\n    n = (plus) ? n : -n;\n    while (n > 0) {\n        if ((n & 1) == 1)\n            r *= x;\n        n /= 2;\n        x *= x;\n    }\n    return plus ? r : 1.0 / r;\n}\n#endif\n#ifdef NK_DTOA_NEEDED\nNK_LIB int\nnk_ifloord(double x)\n{\n    x = (double)((int)x - ((x < 0.0) ? 1 : 0));\n    return (int)x;\n}\n#endif\nNK_LIB int\nnk_ifloorf(float x)\n{\n    x = (float)((int)x - ((x < 0.0f) ? 1 : 0));\n    return (int)x;\n}\nNK_LIB int\nnk_iceilf(float x)\n{\n    if (x >= 0) {\n        int i = (int)x;\n        return (x > i) ? i+1: i;\n    } else {\n        int t = (int)x;\n        float r = x - (float)t;\n        return (r > 0.0f) ? t+1: t;\n    }\n}\n#ifdef NK_DTOA_NEEDED\nNK_LIB int\nnk_log10(double n)\n{\n    int neg;\n    int ret;\n    int exp = 0;\n\n    neg = (n < 0) ? 1 : 0;\n    ret = (neg) ? (int)-n : (int)n;\n    while ((ret / 10) > 0) {\n        ret /= 10;\n        exp++;\n    }\n    if (neg) exp = -exp;\n    return exp;\n}\n#endif\nNK_LIB float\nnk_roundf(float x)\n{\n    return (x >= 0.0f) ? (float)nk_ifloorf(x + 0.5f) : (float)nk_iceilf(x - 0.5f);\n}\nNK_API struct nk_rect\nnk_get_null_rect(void)\n{\n    return nk_null_rect;\n}\nNK_API struct nk_rect\nnk_rect(float x, float y, float w, float h)\n{\n    struct nk_rect r;\n    r.x = x; r.y = y;\n    r.w = w; r.h = h;\n    return r;\n}\nNK_API struct nk_rect\nnk_recti(int x, int y, int w, int h)\n{\n    struct nk_rect r;\n    r.x = (float)x;\n    r.y = (float)y;\n    r.w = (float)w;\n    r.h = (float)h;\n    return r;\n}\nNK_API struct nk_rect\nnk_recta(struct nk_vec2 pos, struct nk_vec2 size)\n{\n    return nk_rect(pos.x, pos.y, size.x, size.y);\n}\nNK_API struct nk_rect\nnk_rectv(const float *r)\n{\n    return nk_rect(r[0], r[1], r[2], r[3]);\n}\nNK_API struct nk_rect\nnk_rectiv(const int *r)\n{\n    return nk_recti(r[0], r[1], r[2], r[3]);\n}\nNK_API struct nk_vec2\nnk_rect_pos(struct nk_rect r)\n{\n    struct nk_vec2 ret;\n    ret.x = r.x; ret.y = r.y;\n    return ret;\n}\nNK_API struct nk_vec2\nnk_rect_size(struct nk_rect r)\n{\n    struct nk_vec2 ret;\n    ret.x = r.w; ret.y = r.h;\n    return ret;\n}\nNK_LIB struct nk_rect\nnk_shrink_rect(struct nk_rect r, float amount)\n{\n    struct nk_rect res;\n    r.w = NK_MAX(r.w, 2 * amount);\n    r.h = NK_MAX(r.h, 2 * amount);\n    res.x = r.x + amount;\n    res.y = r.y + amount;\n    res.w = r.w - 2 * amount;\n    res.h = r.h - 2 * amount;\n    return res;\n}\nNK_LIB struct nk_rect\nnk_pad_rect(struct nk_rect r, struct nk_vec2 pad)\n{\n    r.w = NK_MAX(r.w, 2 * pad.x);\n    r.h = NK_MAX(r.h, 2 * pad.y);\n    r.x += pad.x; r.y += pad.y;\n    r.w -= 2 * pad.x;\n    r.h -= 2 * pad.y;\n    return r;\n}\nNK_API struct nk_vec2\nnk_vec2(float x, float y)\n{\n    struct nk_vec2 ret;\n    ret.x = x; ret.y = y;\n    return ret;\n}\nNK_API struct nk_vec2\nnk_vec2i(int x, int y)\n{\n    struct nk_vec2 ret;\n    ret.x = (float)x;\n    ret.y = (float)y;\n    return ret;\n}\nNK_API struct nk_vec2\nnk_vec2v(const float *v)\n{\n    return nk_vec2(v[0], v[1]);\n}\nNK_API struct nk_vec2\nnk_vec2iv(const int *v)\n{\n    return nk_vec2i(v[0], v[1]);\n}\nNK_LIB void\nnk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0,\n    float x1, float y1)\n{\n    NK_ASSERT(a);\n    NK_ASSERT(clip);\n    clip->x = NK_MAX(a->x, x0);\n    clip->y = NK_MAX(a->y, y0);\n    clip->w = NK_MIN(a->x + a->w, x1) - clip->x;\n    clip->h = NK_MIN(a->y + a->h, y1) - clip->y;\n    clip->w = NK_MAX(0, clip->w);\n    clip->h = NK_MAX(0, clip->h);\n}\n\nNK_API void\nnk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r,\n    float pad_x, float pad_y, enum nk_heading direction)\n{\n    float w_half, h_half;\n    NK_ASSERT(result);\n\n    r.w = NK_MAX(2 * pad_x, r.w);\n    r.h = NK_MAX(2 * pad_y, r.h);\n    r.w = r.w - 2 * pad_x;\n    r.h = r.h - 2 * pad_y;\n\n    r.x = r.x + pad_x;\n    r.y = r.y + pad_y;\n\n    w_half = r.w / 2.0f;\n    h_half = r.h / 2.0f;\n\n    if (direction == NK_UP) {\n        result[0] = nk_vec2(r.x + w_half, r.y);\n        result[1] = nk_vec2(r.x + r.w, r.y + r.h);\n        result[2] = nk_vec2(r.x, r.y + r.h);\n    } else if (direction == NK_RIGHT) {\n        result[0] = nk_vec2(r.x, r.y);\n        result[1] = nk_vec2(r.x + r.w, r.y + h_half);\n        result[2] = nk_vec2(r.x, r.y + r.h);\n    } else if (direction == NK_DOWN) {\n        result[0] = nk_vec2(r.x, r.y);\n        result[1] = nk_vec2(r.x + r.w, r.y);\n        result[2] = nk_vec2(r.x + w_half, r.y + r.h);\n    } else {\n        result[0] = nk_vec2(r.x, r.y + h_half);\n        result[1] = nk_vec2(r.x + r.w, r.y);\n        result[2] = nk_vec2(r.x + r.w, r.y + r.h);\n    }\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                              UTIL\n *\n * ===============================================================*/\nNK_INTERN int nk_str_match_here(const char *regexp, const char *text);\nNK_INTERN int nk_str_match_star(int c, const char *regexp, const char *text);\nNK_LIB nk_bool nk_is_lower(int c) {return (c >= 'a' && c <= 'z') || (c >= 0xE0 && c <= 0xFF);}\nNK_LIB nk_bool nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 && c <= 0xDF);}\nNK_LIB int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;}\nNK_LIB int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;}\n\n#ifdef NK_MEMCPY_NEEDED\nNK_LIB void*\nnk_memcopy(void *dst0, const void *src0, nk_size length)\n{\n    nk_ptr t;\n    char *dst = (char*)dst0;\n    const char *src = (const char*)src0;\n    if (length == 0 || dst == src)\n        goto done;\n\n    #define nk_word int\n    #define nk_wsize sizeof(nk_word)\n    #define nk_wmask (nk_wsize-1)\n    #define NK_TLOOP(s) if (t) NK_TLOOP1(s)\n    #define NK_TLOOP1(s) do { s; } while (--t)\n\n    if (dst < src) {\n        t = (nk_ptr)src; /* only need low bits */\n        if ((t | (nk_ptr)dst) & nk_wmask) {\n            if ((t ^ (nk_ptr)dst) & nk_wmask || length < nk_wsize)\n                t = length;\n            else\n                t = nk_wsize - (t & nk_wmask);\n            length -= t;\n            NK_TLOOP1(*dst++ = *src++);\n        }\n        t = length / nk_wsize;\n        NK_TLOOP(*(nk_word*)(void*)dst = *(const nk_word*)(const void*)src;\n            src += nk_wsize; dst += nk_wsize);\n        t = length & nk_wmask;\n        NK_TLOOP(*dst++ = *src++);\n    } else {\n        src += length;\n        dst += length;\n        t = (nk_ptr)src;\n        if ((t | (nk_ptr)dst) & nk_wmask) {\n            if ((t ^ (nk_ptr)dst) & nk_wmask || length <= nk_wsize)\n                t = length;\n            else\n                t &= nk_wmask;\n            length -= t;\n            NK_TLOOP1(*--dst = *--src);\n        }\n        t = length / nk_wsize;\n        NK_TLOOP(src -= nk_wsize; dst -= nk_wsize;\n            *(nk_word*)(void*)dst = *(const nk_word*)(const void*)src);\n        t = length & nk_wmask;\n        NK_TLOOP(*--dst = *--src);\n    }\n    #undef nk_word\n    #undef nk_wsize\n    #undef nk_wmask\n    #undef NK_TLOOP\n    #undef NK_TLOOP1\ndone:\n    return (dst0);\n}\n#endif\n#ifdef NK_MEMSET_NEEDED\nNK_LIB void\nnk_memset(void *ptr, int c0, nk_size size)\n{\n    #define nk_word unsigned\n    #define nk_wsize sizeof(nk_word)\n    #define nk_wmask (nk_wsize - 1)\n    nk_byte *dst = (nk_byte*)ptr;\n    unsigned c = 0;\n    nk_size t = 0;\n\n    if ((c = (nk_byte)c0) != 0) {\n        c = (c << 8) | c; /* at least 16-bits  */\n        if (sizeof(unsigned int) > 2)\n            c = (c << 16) | c; /* at least 32-bits*/\n    }\n\n    /* too small of a word count */\n    dst = (nk_byte*)ptr;\n    if (size < 3 * nk_wsize) {\n        while (size--) *dst++ = (nk_byte)c0;\n        return;\n    }\n\n    /* align destination */\n    if ((t = NK_PTR_TO_UINT(dst) & nk_wmask) != 0) {\n        t = nk_wsize -t;\n        size -= t;\n        do {\n            *dst++ = (nk_byte)c0;\n        } while (--t != 0);\n    }\n\n    /* fill word */\n    t = size / nk_wsize;\n    do {\n        *(nk_word*)((void*)dst) = c;\n        dst += nk_wsize;\n    } while (--t != 0);\n\n    /* fill trailing bytes */\n    t = (size & nk_wmask);\n    if (t != 0) {\n        do {\n            *dst++ = (nk_byte)c0;\n        } while (--t != 0);\n    }\n\n    #undef nk_word\n    #undef nk_wsize\n    #undef nk_wmask\n}\n#endif\nNK_LIB void\nnk_zero(void *ptr, nk_size size)\n{\n    NK_ASSERT(ptr);\n    NK_MEMSET(ptr, 0, size);\n}\nNK_API int\nnk_strlen(const char *str)\n{\n    int siz = 0;\n    NK_ASSERT(str);\n    while (str && *str++ != '\\0') siz++;\n    return siz;\n}\nNK_API int\nnk_strtoi(const char *str, char **endptr)\n{\n    int neg = 1;\n    const char *p = str;\n    int value = 0;\n\n    NK_ASSERT(str);\n    if (!str) return 0;\n\n    /* skip whitespace */\n    while (*p == ' ') p++;\n    if (*p == '-') {\n        neg = -1;\n        p++;\n    }\n    while (*p && *p >= '0' && *p <= '9') {\n        value = value * 10 + (int) (*p - '0');\n        p++;\n    }\n    if (endptr)\n        *endptr = (char *)p;\n    return neg*value;\n}\n#ifdef NK_STRTOD_NEEDED\nNK_API double\nnk_strtod(const char *str, char **endptr)\n{\n    double m;\n    double neg = 1.0;\n    char *p = (char *)str;\n    double value = 0;\n    double number = 0;\n\n    NK_ASSERT(str);\n    if (!str) return 0;\n\n    /* skip whitespace */\n    while (*p == ' ') p++;\n    if (*p == '-') {\n        neg = -1.0;\n        p++;\n    }\n\n    while (*p && *p != '.' && *p != 'e') {\n        value = value * 10.0 + (double) (*p - '0');\n        p++;\n    }\n\n    if (*p == '.') {\n        p++;\n        for(m = 0.1; *p && *p != 'e'; p++ ) {\n            value = value + (double) (*p - '0') * m;\n            m *= 0.1;\n        }\n    }\n    if (*p == 'e') {\n        int i, pow, div;\n        p++;\n        if (*p == '-') {\n            div = nk_true;\n            p++;\n        } else if (*p == '+') {\n            div = nk_false;\n            p++;\n        } else div = nk_false;\n\n        for (pow = 0; *p; p++)\n            pow = pow * 10 + (int) (*p - '0');\n\n        for (m = 1.0, i = 0; i < pow; i++)\n            m *= 10.0;\n\n        if (div)\n            value /= m;\n        else value *= m;\n    }\n    number = value * neg;\n    if (endptr)\n        *endptr = (char *)p;\n    return number;\n}\n#endif\nNK_API float\nnk_strtof(const char *str, char **endptr)\n{\n    float float_value;\n    double double_value;\n    double_value = NK_STRTOD(str, endptr);\n    float_value = (float)double_value;\n    return float_value;\n}\nNK_API int\nnk_stricmp(const char *s1, const char *s2)\n{\n    nk_int c1,c2,d;\n    do {\n        c1 = *s1++;\n        c2 = *s2++;\n        d = c1 - c2;\n        while (d) {\n            if (c1 <= 'Z' && c1 >= 'A') {\n                d += ('a' - 'A');\n                if (!d) break;\n            }\n            if (c2 <= 'Z' && c2 >= 'A') {\n                d -= ('a' - 'A');\n                if (!d) break;\n            }\n            return ((d >= 0) << 1) - 1;\n        }\n    } while (c1);\n    return 0;\n}\nNK_API int\nnk_stricmpn(const char *s1, const char *s2, int n)\n{\n    int c1,c2,d;\n    NK_ASSERT(n >= 0);\n    do {\n        c1 = *s1++;\n        c2 = *s2++;\n        if (!n--) return 0;\n\n        d = c1 - c2;\n        while (d) {\n            if (c1 <= 'Z' && c1 >= 'A') {\n                d += ('a' - 'A');\n                if (!d) break;\n            }\n            if (c2 <= 'Z' && c2 >= 'A') {\n                d -= ('a' - 'A');\n                if (!d) break;\n            }\n            return ((d >= 0) << 1) - 1;\n        }\n    } while (c1);\n    return 0;\n}\nNK_INTERN int\nnk_str_match_here(const char *regexp, const char *text)\n{\n    if (regexp[0] == '\\0')\n        return 1;\n    if (regexp[1] == '*')\n        return nk_str_match_star(regexp[0], regexp+2, text);\n    if (regexp[0] == '$' && regexp[1] == '\\0')\n        return *text == '\\0';\n    if (*text!='\\0' && (regexp[0]=='.' || regexp[0]==*text))\n        return nk_str_match_here(regexp+1, text+1);\n    return 0;\n}\nNK_INTERN int\nnk_str_match_star(int c, const char *regexp, const char *text)\n{\n    do {/* a '* matches zero or more instances */\n        if (nk_str_match_here(regexp, text))\n            return 1;\n    } while (*text != '\\0' && (*text++ == c || c == '.'));\n    return 0;\n}\nNK_API int\nnk_strfilter(const char *text, const char *regexp)\n{\n    /*\n    c    matches any literal character c\n    .    matches any single character\n    ^    matches the beginning of the input string\n    $    matches the end of the input string\n    *    matches zero or more occurrences of the previous character*/\n    if (regexp[0] == '^')\n        return nk_str_match_here(regexp+1, text);\n    do {    /* must look even if string is empty */\n        if (nk_str_match_here(regexp, text))\n            return 1;\n    } while (*text++ != '\\0');\n    return 0;\n}\nNK_API int\nnk_strmatch_fuzzy_text(const char *str, int str_len,\n    const char *pattern, int *out_score)\n{\n    /* Returns true if each character in pattern is found sequentially within str\n     * if found then out_score is also set. Score value has no intrinsic meaning.\n     * Range varies with pattern. Can only compare scores with same search pattern. */\n\n    /* bonus for adjacent matches */\n    #define NK_ADJACENCY_BONUS 5\n    /* bonus if match occurs after a separator */\n    #define NK_SEPARATOR_BONUS 10\n    /* bonus if match is uppercase and prev is lower */\n    #define NK_CAMEL_BONUS 10\n    /* penalty applied for every letter in str before the first match */\n    #define NK_LEADING_LETTER_PENALTY (-3)\n    /* maximum penalty for leading letters */\n    #define NK_MAX_LEADING_LETTER_PENALTY (-9)\n    /* penalty for every letter that doesn't matter */\n    #define NK_UNMATCHED_LETTER_PENALTY (-1)\n\n    /* loop variables */\n    int score = 0;\n    char const * pattern_iter = pattern;\n    int str_iter = 0;\n    int prev_matched = nk_false;\n    int prev_lower = nk_false;\n    /* true so if first letter match gets separator bonus*/\n    int prev_separator = nk_true;\n\n    /* use \"best\" matched letter if multiple string letters match the pattern */\n    char const * best_letter = 0;\n    int best_letter_score = 0;\n\n    /* loop over strings */\n    NK_ASSERT(str);\n    NK_ASSERT(pattern);\n    if (!str || !str_len || !pattern) return 0;\n    while (str_iter < str_len)\n    {\n        const char pattern_letter = *pattern_iter;\n        const char str_letter = str[str_iter];\n\n        int next_match = *pattern_iter != '\\0' &&\n            nk_to_lower(pattern_letter) == nk_to_lower(str_letter);\n        int rematch = best_letter && nk_to_upper(*best_letter) == nk_to_upper(str_letter);\n\n        int advanced = next_match && best_letter;\n        int pattern_repeat = best_letter && *pattern_iter != '\\0';\n        pattern_repeat = pattern_repeat &&\n            nk_to_lower(*best_letter) == nk_to_lower(pattern_letter);\n\n        if (advanced || pattern_repeat) {\n            score += best_letter_score;\n            best_letter = 0;\n            best_letter_score = 0;\n        }\n\n        if (next_match || rematch)\n        {\n            int new_score = 0;\n            /* Apply penalty for each letter before the first pattern match */\n            if (pattern_iter == pattern) {\n                int count = (int)(&str[str_iter] - str);\n                int penalty = NK_LEADING_LETTER_PENALTY * count;\n                if (penalty < NK_MAX_LEADING_LETTER_PENALTY)\n                    penalty = NK_MAX_LEADING_LETTER_PENALTY;\n\n                score += penalty;\n            }\n\n            /* apply bonus for consecutive bonuses */\n            if (prev_matched)\n                new_score += NK_ADJACENCY_BONUS;\n\n            /* apply bonus for matches after a separator */\n            if (prev_separator)\n                new_score += NK_SEPARATOR_BONUS;\n\n            /* apply bonus across camel case boundaries */\n            if (prev_lower && nk_is_upper(str_letter))\n                new_score += NK_CAMEL_BONUS;\n\n            /* update pattern iter IFF the next pattern letter was matched */\n            if (next_match)\n                ++pattern_iter;\n\n            /* update best letter in str which may be for a \"next\" letter or a rematch */\n            if (new_score >= best_letter_score) {\n                /* apply penalty for now skipped letter */\n                if (best_letter != 0)\n                    score += NK_UNMATCHED_LETTER_PENALTY;\n\n                best_letter = &str[str_iter];\n                best_letter_score = new_score;\n            }\n            prev_matched = nk_true;\n        } else {\n            score += NK_UNMATCHED_LETTER_PENALTY;\n            prev_matched = nk_false;\n        }\n\n        /* separators should be more easily defined */\n        prev_lower = nk_is_lower(str_letter) != 0;\n        prev_separator = str_letter == '_' || str_letter == ' ';\n\n        ++str_iter;\n    }\n\n    /* apply score for last match */\n    if (best_letter)\n        score += best_letter_score;\n\n    /* did not match full pattern */\n    if (*pattern_iter != '\\0')\n        return nk_false;\n\n    if (out_score)\n        *out_score = score;\n    return nk_true;\n}\nNK_API int\nnk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score)\n{\n    return nk_strmatch_fuzzy_text(str, nk_strlen(str), pattern, out_score);\n}\nNK_LIB int\nnk_string_float_limit(char *string, int prec)\n{\n    int dot = 0;\n    char *c = string;\n    while (*c) {\n        if (*c == '.') {\n            dot = 1;\n            c++;\n            continue;\n        }\n        if (dot == (prec+1)) {\n            *c = 0;\n            break;\n        }\n        if (dot > 0) dot++;\n        c++;\n    }\n    return (int)(c - string);\n}\nNK_INTERN void\nnk_strrev_ascii(char *s)\n{\n    int len = nk_strlen(s);\n    int end = len / 2;\n    int i = 0;\n    char t;\n    for (; i < end; ++i) {\n        t = s[i];\n        s[i] = s[len - 1 - i];\n        s[len -1 - i] = t;\n    }\n}\nNK_LIB char*\nnk_itoa(char *s, long n)\n{\n    long i = 0;\n    if (n == 0) {\n        s[i++] = '0';\n        s[i] = 0;\n        return s;\n    }\n    if (n < 0) {\n        s[i++] = '-';\n        n = -n;\n    }\n    while (n > 0) {\n        s[i++] = (char)('0' + (n % 10));\n        n /= 10;\n    }\n    s[i] = 0;\n    if (s[0] == '-')\n        ++s;\n\n    nk_strrev_ascii(s);\n    return s;\n}\n#ifdef NK_DTOA_NEEDED\nNK_LIB char*\nnk_dtoa(char *s, double n)\n{\n    int useExp = 0;\n    int digit = 0, m = 0, m1 = 0;\n    char *c = s;\n    int neg = 0;\n\n    NK_ASSERT(s);\n    if (!s) return 0;\n\n    if (n == 0.0) {\n        s[0] = '0'; s[1] = '\\0';\n        return s;\n    }\n\n    neg = (n < 0);\n    if (neg) n = -n;\n\n    /* calculate magnitude */\n    m = nk_log10(n);\n    useExp = (m >= 14 || (neg && m >= 9) || m <= -9);\n    if (neg) *(c++) = '-';\n\n    /* set up for scientific notation */\n    if (useExp) {\n        if (m < 0)\n           m -= 1;\n        n = n / (double)nk_pow(10.0, m);\n        m1 = m;\n        m = 0;\n    }\n    if (m < 1.0) {\n        m = 0;\n    }\n\n    /* convert the number */\n    while (n > NK_FLOAT_PRECISION || m >= 0) {\n        double weight = nk_pow(10.0, m);\n        if (weight > 0) {\n            double t = (double)n / weight;\n            digit = nk_ifloord(t);\n            n -= ((double)digit * weight);\n            *(c++) = (char)('0' + (char)digit);\n        }\n        if (m == 0 && n > 0)\n            *(c++) = '.';\n        m--;\n    }\n\n    if (useExp) {\n        /* convert the exponent */\n        int i, j;\n        *(c++) = 'e';\n        if (m1 > 0) {\n            *(c++) = '+';\n        } else {\n            *(c++) = '-';\n            m1 = -m1;\n        }\n        m = 0;\n        while (m1 > 0) {\n            *(c++) = (char)('0' + (char)(m1 % 10));\n            m1 /= 10;\n            m++;\n        }\n        c -= m;\n        for (i = 0, j = m-1; i<j; i++, j--) {\n            /* swap without temporary */\n            c[i] ^= c[j];\n            c[j] ^= c[i];\n            c[i] ^= c[j];\n        }\n        c += m;\n    }\n    *(c) = '\\0';\n    return s;\n}\n#endif\n#ifdef NK_INCLUDE_STANDARD_VARARGS\n#ifndef NK_INCLUDE_STANDARD_IO\nNK_INTERN int\nnk_vsnprintf(char *buf, int buf_size, const char *fmt, va_list args)\n{\n    enum nk_arg_type {\n        NK_ARG_TYPE_CHAR,\n        NK_ARG_TYPE_SHORT,\n        NK_ARG_TYPE_DEFAULT,\n        NK_ARG_TYPE_LONG\n    };\n    enum nk_arg_flags {\n        NK_ARG_FLAG_LEFT = 0x01,\n        NK_ARG_FLAG_PLUS = 0x02,\n        NK_ARG_FLAG_SPACE = 0x04,\n        NK_ARG_FLAG_NUM = 0x10,\n        NK_ARG_FLAG_ZERO = 0x20\n    };\n\n    char number_buffer[NK_MAX_NUMBER_BUFFER];\n    enum nk_arg_type arg_type = NK_ARG_TYPE_DEFAULT;\n    int precision = NK_DEFAULT;\n    int width = NK_DEFAULT;\n    nk_flags flag = 0;\n\n    int len = 0;\n    int result = -1;\n    const char *iter = fmt;\n\n    NK_ASSERT(buf);\n    NK_ASSERT(buf_size);\n    if (!buf || !buf_size || !fmt) return 0;\n    for (iter = fmt; *iter && len < buf_size; iter++) {\n        /* copy all non-format characters */\n        while (*iter && (*iter != '%') && (len < buf_size))\n            buf[len++] = *iter++;\n        if (!(*iter) || len >= buf_size) break;\n        iter++;\n\n        /* flag arguments */\n        while (*iter) {\n            if (*iter == '-') flag |= NK_ARG_FLAG_LEFT;\n            else if (*iter == '+') flag |= NK_ARG_FLAG_PLUS;\n            else if (*iter == ' ') flag |= NK_ARG_FLAG_SPACE;\n            else if (*iter == '#') flag |= NK_ARG_FLAG_NUM;\n            else if (*iter == '0') flag |= NK_ARG_FLAG_ZERO;\n            else break;\n            iter++;\n        }\n\n        /* width argument */\n        width = NK_DEFAULT;\n        if (*iter >= '1' && *iter <= '9') {\n            char *end;\n            width = nk_strtoi(iter, &end);\n            if (end == iter)\n                width = -1;\n            else iter = end;\n        } else if (*iter == '*') {\n            width = va_arg(args, int);\n            iter++;\n        }\n\n        /* precision argument */\n        precision = NK_DEFAULT;\n        if (*iter == '.') {\n            iter++;\n            if (*iter == '*') {\n                precision = va_arg(args, int);\n                iter++;\n            } else {\n                char *end;\n                precision = nk_strtoi(iter, &end);\n                if (end == iter)\n                    precision = -1;\n                else iter = end;\n            }\n        }\n\n        /* length modifier */\n        if (*iter == 'h') {\n            if (*(iter+1) == 'h') {\n                arg_type = NK_ARG_TYPE_CHAR;\n                iter++;\n            } else arg_type = NK_ARG_TYPE_SHORT;\n            iter++;\n        } else if (*iter == 'l') {\n            arg_type = NK_ARG_TYPE_LONG;\n            iter++;\n        } else arg_type = NK_ARG_TYPE_DEFAULT;\n\n        /* specifier */\n        if (*iter == '%') {\n            NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);\n            NK_ASSERT(precision == NK_DEFAULT);\n            NK_ASSERT(width == NK_DEFAULT);\n            if (len < buf_size)\n                buf[len++] = '%';\n        } else if (*iter == 's') {\n            /* string  */\n            const char *str = va_arg(args, const char*);\n            NK_ASSERT(str != buf && \"buffer and argument are not allowed to overlap!\");\n            NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);\n            NK_ASSERT(precision == NK_DEFAULT);\n            NK_ASSERT(width == NK_DEFAULT);\n            if (str == buf) return -1;\n            while (str && *str && len < buf_size)\n                buf[len++] = *str++;\n        } else if (*iter == 'n') {\n            /* current length callback */\n            signed int *n = va_arg(args, int*);\n            NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);\n            NK_ASSERT(precision == NK_DEFAULT);\n            NK_ASSERT(width == NK_DEFAULT);\n            if (n) *n = len;\n        } else if (*iter == 'c' || *iter == 'i' || *iter == 'd') {\n            /* signed integer */\n            long value = 0;\n            const char *num_iter;\n            int num_len, num_print, padding;\n            int cur_precision = NK_MAX(precision, 1);\n            int cur_width = NK_MAX(width, 0);\n\n            /* retrieve correct value type */\n            if (arg_type == NK_ARG_TYPE_CHAR)\n                value = (signed char)va_arg(args, int);\n            else if (arg_type == NK_ARG_TYPE_SHORT)\n                value = (signed short)va_arg(args, int);\n            else if (arg_type == NK_ARG_TYPE_LONG)\n                value = va_arg(args, signed long);\n            else if (*iter == 'c')\n                value = (unsigned char)va_arg(args, int);\n            else value = va_arg(args, signed int);\n\n            /* convert number to string */\n            nk_itoa(number_buffer, value);\n            num_len = nk_strlen(number_buffer);\n            padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0);\n            if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE))\n                padding = NK_MAX(padding-1, 0);\n\n            /* fill left padding up to a total of `width` characters */\n            if (!(flag & NK_ARG_FLAG_LEFT)) {\n                while (padding-- > 0 && (len < buf_size)) {\n                    if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))\n                        buf[len++] = '0';\n                    else buf[len++] = ' ';\n                }\n            }\n\n            /* copy string value representation into buffer */\n            if ((flag & NK_ARG_FLAG_PLUS) && value >= 0 && len < buf_size)\n                buf[len++] = '+';\n            else if ((flag & NK_ARG_FLAG_SPACE) && value >= 0 && len < buf_size)\n                buf[len++] = ' ';\n\n            /* fill up to precision number of digits with '0' */\n            num_print = NK_MAX(cur_precision, num_len);\n            while (precision && (num_print > num_len) && (len < buf_size)) {\n                buf[len++] = '0';\n                num_print--;\n            }\n\n            /* copy string value representation into buffer */\n            num_iter = number_buffer;\n            while (precision && *num_iter && len < buf_size)\n                buf[len++] = *num_iter++;\n\n            /* fill right padding up to width characters */\n            if (flag & NK_ARG_FLAG_LEFT) {\n                while ((padding-- > 0) && (len < buf_size))\n                    buf[len++] = ' ';\n            }\n        } else if (*iter == 'o' || *iter == 'x' || *iter == 'X' || *iter == 'u') {\n            /* unsigned integer */\n            unsigned long value = 0;\n            int num_len = 0, num_print, padding = 0;\n            int cur_precision = NK_MAX(precision, 1);\n            int cur_width = NK_MAX(width, 0);\n            unsigned int base = (*iter == 'o') ? 8: (*iter == 'u')? 10: 16;\n\n            /* print oct/hex/dec value */\n            const char *upper_output_format = \"0123456789ABCDEF\";\n            const char *lower_output_format = \"0123456789abcdef\";\n            const char *output_format = (*iter == 'x') ?\n                lower_output_format: upper_output_format;\n\n            /* retrieve correct value type */\n            if (arg_type == NK_ARG_TYPE_CHAR)\n                value = (unsigned char)va_arg(args, int);\n            else if (arg_type == NK_ARG_TYPE_SHORT)\n                value = (unsigned short)va_arg(args, int);\n            else if (arg_type == NK_ARG_TYPE_LONG)\n                value = va_arg(args, unsigned long);\n            else value = va_arg(args, unsigned int);\n\n            do {\n                /* convert decimal number into hex/oct number */\n                int digit = output_format[value % base];\n                if (num_len < NK_MAX_NUMBER_BUFFER)\n                    number_buffer[num_len++] = (char)digit;\n                value /= base;\n            } while (value > 0);\n\n            num_print = NK_MAX(cur_precision, num_len);\n            padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0);\n            if (flag & NK_ARG_FLAG_NUM)\n                padding = NK_MAX(padding-1, 0);\n\n            /* fill left padding up to a total of `width` characters */\n            if (!(flag & NK_ARG_FLAG_LEFT)) {\n                while ((padding-- > 0) && (len < buf_size)) {\n                    if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))\n                        buf[len++] = '0';\n                    else buf[len++] = ' ';\n                }\n            }\n\n            /* fill up to precision number of digits */\n            if (num_print && (flag & NK_ARG_FLAG_NUM)) {\n                if ((*iter == 'o') && (len < buf_size)) {\n                    buf[len++] = '0';\n                } else if ((*iter == 'x') && ((len+1) < buf_size)) {\n                    buf[len++] = '0';\n                    buf[len++] = 'x';\n                } else if ((*iter == 'X') && ((len+1) < buf_size)) {\n                    buf[len++] = '0';\n                    buf[len++] = 'X';\n                }\n            }\n            while (precision && (num_print > num_len) && (len < buf_size)) {\n                buf[len++] = '0';\n                num_print--;\n            }\n\n            /* reverse number direction */\n            while (num_len > 0) {\n                if (precision && (len < buf_size))\n                    buf[len++] = number_buffer[num_len-1];\n                num_len--;\n            }\n\n            /* fill right padding up to width characters */\n            if (flag & NK_ARG_FLAG_LEFT) {\n                while ((padding-- > 0) && (len < buf_size))\n                    buf[len++] = ' ';\n            }\n        } else if (*iter == 'f') {\n            /* floating point */\n            const char *num_iter;\n            int cur_precision = (precision < 0) ? 6: precision;\n            int prefix, cur_width = NK_MAX(width, 0);\n            double value = va_arg(args, double);\n            int num_len = 0, frac_len = 0, dot = 0;\n            int padding = 0;\n\n            NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);\n            NK_DTOA(number_buffer, value);\n            num_len = nk_strlen(number_buffer);\n\n            /* calculate padding */\n            num_iter = number_buffer;\n            while (*num_iter && *num_iter != '.')\n                num_iter++;\n\n            prefix = (*num_iter == '.')?(int)(num_iter - number_buffer)+1:0;\n            padding = NK_MAX(cur_width - (prefix + NK_MIN(cur_precision, num_len - prefix)) , 0);\n            if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE))\n                padding = NK_MAX(padding-1, 0);\n\n            /* fill left padding up to a total of `width` characters */\n            if (!(flag & NK_ARG_FLAG_LEFT)) {\n                while (padding-- > 0 && (len < buf_size)) {\n                    if (flag & NK_ARG_FLAG_ZERO)\n                        buf[len++] = '0';\n                    else buf[len++] = ' ';\n                }\n            }\n\n            /* copy string value representation into buffer */\n            num_iter = number_buffer;\n            if ((flag & NK_ARG_FLAG_PLUS) && (value >= 0) && (len < buf_size))\n                buf[len++] = '+';\n            else if ((flag & NK_ARG_FLAG_SPACE) && (value >= 0) && (len < buf_size))\n                buf[len++] = ' ';\n            while (*num_iter) {\n                if (dot) frac_len++;\n                if (len < buf_size)\n                    buf[len++] = *num_iter;\n                if (*num_iter == '.') dot = 1;\n                if (frac_len >= cur_precision) break;\n                num_iter++;\n            }\n\n            /* fill number up to precision */\n            while (frac_len < cur_precision) {\n                if (!dot && len < buf_size) {\n                    buf[len++] = '.';\n                    dot = 1;\n                }\n                if (len < buf_size)\n                    buf[len++] = '0';\n                frac_len++;\n            }\n\n            /* fill right padding up to width characters */\n            if (flag & NK_ARG_FLAG_LEFT) {\n                while ((padding-- > 0) && (len < buf_size))\n                    buf[len++] = ' ';\n            }\n        } else {\n            /* Specifier not supported: g,G,e,E,p,z */\n            NK_ASSERT(0 && \"specifier is not supported!\");\n            return result;\n        }\n    }\n    buf[(len >= buf_size)?(buf_size-1):len] = 0;\n    result = (len >= buf_size)?-1:len;\n    return result;\n}\n#endif\nNK_LIB int\nnk_strfmt(char *buf, int buf_size, const char *fmt, va_list args)\n{\n    int result = -1;\n    NK_ASSERT(buf);\n    NK_ASSERT(buf_size);\n    if (!buf || !buf_size || !fmt) return 0;\n#ifdef NK_INCLUDE_STANDARD_IO\n    result = NK_VSNPRINTF(buf, (nk_size)buf_size, fmt, args);\n    result = (result >= buf_size) ? -1: result;\n    buf[buf_size-1] = 0;\n#else\n    result = nk_vsnprintf(buf, buf_size, fmt, args);\n#endif\n    return result;\n}\n#endif\nNK_API nk_hash\nnk_murmur_hash(const void * key, int len, nk_hash seed)\n{\n    /* 32-Bit MurmurHash3: https://code.google.com/p/smhasher/wiki/MurmurHash3*/\n    #define NK_ROTL(x,r) ((x) << (r) | ((x) >> (32 - r)))\n\n    nk_uint h1 = seed;\n    nk_uint k1;\n    const nk_byte *data = (const nk_byte*)key;\n    const nk_byte *keyptr = data;\n    nk_byte *k1ptr;\n    const int bsize = sizeof(k1);\n    const int nblocks = len/4;\n\n    const nk_uint c1 = 0xcc9e2d51;\n    const nk_uint c2 = 0x1b873593;\n    const nk_byte *tail;\n    int i;\n\n    /* body */\n    if (!key) return 0;\n    for (i = 0; i < nblocks; ++i, keyptr += bsize) {\n        k1ptr = (nk_byte*)&k1;\n        k1ptr[0] = keyptr[0];\n        k1ptr[1] = keyptr[1];\n        k1ptr[2] = keyptr[2];\n        k1ptr[3] = keyptr[3];\n\n        k1 *= c1;\n        k1 = NK_ROTL(k1,15);\n        k1 *= c2;\n\n        h1 ^= k1;\n        h1 = NK_ROTL(h1,13);\n        h1 = h1*5+0xe6546b64;\n    }\n\n    /* tail */\n    tail = (const nk_byte*)(data + nblocks*4);\n    k1 = 0;\n    switch (len & 3) {\n        case 3: k1 ^= (nk_uint)(tail[2] << 16); /* fallthrough */\n        case 2: k1 ^= (nk_uint)(tail[1] << 8u); /* fallthrough */\n        case 1: k1 ^= tail[0];\n            k1 *= c1;\n            k1 = NK_ROTL(k1,15);\n            k1 *= c2;\n            h1 ^= k1;\n            break;\n        default: break;\n    }\n\n    /* finalization */\n    h1 ^= (nk_uint)len;\n    /* fmix32 */\n    h1 ^= h1 >> 16;\n    h1 *= 0x85ebca6b;\n    h1 ^= h1 >> 13;\n    h1 *= 0xc2b2ae35;\n    h1 ^= h1 >> 16;\n\n    #undef NK_ROTL\n    return h1;\n}\n#ifdef NK_INCLUDE_STANDARD_IO\nNK_LIB char*\nnk_file_load(const char* path, nk_size* siz, const struct nk_allocator *alloc)\n{\n    char *buf;\n    FILE *fd;\n    long ret;\n\n    NK_ASSERT(path);\n    NK_ASSERT(siz);\n    NK_ASSERT(alloc);\n    if (!path || !siz || !alloc)\n        return 0;\n\n    fd = fopen(path, \"rb\");\n    if (!fd) return 0;\n    fseek(fd, 0, SEEK_END);\n    ret = ftell(fd);\n    if (ret < 0) {\n        fclose(fd);\n        return 0;\n    }\n    *siz = (nk_size)ret;\n    fseek(fd, 0, SEEK_SET);\n    buf = (char*)alloc->alloc(alloc->userdata,0, *siz);\n    NK_ASSERT(buf);\n    if (!buf) {\n        fclose(fd);\n        return 0;\n    }\n    *siz = (nk_size)fread(buf, 1,*siz, fd);\n    fclose(fd);\n    return buf;\n}\n#endif\nNK_LIB int\nnk_text_clamp(const struct nk_user_font *font, const char *text,\n    int text_len, float space, int *glyphs, float *text_width,\n    nk_rune *sep_list, int sep_count)\n{\n    int i = 0;\n    int glyph_len = 0;\n    float last_width = 0;\n    nk_rune unicode = 0;\n    float width = 0;\n    int len = 0;\n    int g = 0;\n    float s;\n\n    int sep_len = 0;\n    int sep_g = 0;\n    float sep_width = 0;\n    sep_count = NK_MAX(sep_count,0);\n\n    glyph_len = nk_utf_decode(text, &unicode, text_len);\n    while (glyph_len && (width < space) && (len < text_len)) {\n        len += glyph_len;\n        s = font->width(font->userdata, font->height, text, len);\n        for (i = 0; i < sep_count; ++i) {\n            if (unicode != sep_list[i]) continue;\n            sep_width = last_width = width;\n            sep_g = g+1;\n            sep_len = len;\n            break;\n        }\n        if (i == sep_count){\n            last_width = sep_width = width;\n            sep_g = g+1;\n        }\n        width = s;\n        glyph_len = nk_utf_decode(&text[len], &unicode, text_len - len);\n        g++;\n    }\n    if (len >= text_len) {\n        *glyphs = g;\n        *text_width = last_width;\n        return len;\n    } else {\n        *glyphs = sep_g;\n        *text_width = sep_width;\n        return (!sep_len) ? len: sep_len;\n    }\n}\nNK_LIB struct nk_vec2\nnk_text_calculate_text_bounds(const struct nk_user_font *font,\n    const char *begin, int byte_len, float row_height, const char **remaining,\n    struct nk_vec2 *out_offset, int *glyphs, int op)\n{\n    float line_height = row_height;\n    struct nk_vec2 text_size = nk_vec2(0,0);\n    float line_width = 0.0f;\n\n    float glyph_width;\n    int glyph_len = 0;\n    nk_rune unicode = 0;\n    int text_len = 0;\n    if (!begin || byte_len <= 0 || !font)\n        return nk_vec2(0,row_height);\n\n    glyph_len = nk_utf_decode(begin, &unicode, byte_len);\n    if (!glyph_len) return text_size;\n    glyph_width = font->width(font->userdata, font->height, begin, glyph_len);\n\n    *glyphs = 0;\n    while ((text_len < byte_len) && glyph_len) {\n        if (unicode == '\\n') {\n            text_size.x = NK_MAX(text_size.x, line_width);\n            text_size.y += line_height;\n            line_width = 0;\n            *glyphs+=1;\n            if (op == NK_STOP_ON_NEW_LINE)\n                break;\n\n            text_len++;\n            glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);\n            continue;\n        }\n\n        if (unicode == '\\r') {\n            text_len++;\n            *glyphs+=1;\n            glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);\n            continue;\n        }\n\n        *glyphs = *glyphs + 1;\n        text_len += glyph_len;\n        line_width += (float)glyph_width;\n        glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);\n        glyph_width = font->width(font->userdata, font->height, begin+text_len, glyph_len);\n        continue;\n    }\n\n    if (text_size.x < line_width)\n        text_size.x = line_width;\n    if (out_offset)\n        *out_offset = nk_vec2(line_width, text_size.y + line_height);\n    if (line_width > 0 || text_size.y == 0.0f)\n        text_size.y += line_height;\n    if (remaining)\n        *remaining = begin+text_len;\n    return text_size;\n}\n\n\n\n\n\n/* ==============================================================\n *\n *                          COLOR\n *\n * ===============================================================*/\nNK_INTERN int\nnk_parse_hex(const char *p, int length)\n{\n    int i = 0;\n    int len = 0;\n    while (len < length) {\n        i <<= 4;\n        if (p[len] >= 'a' && p[len] <= 'f')\n            i += ((p[len] - 'a') + 10);\n        else if (p[len] >= 'A' && p[len] <= 'F')\n            i += ((p[len] - 'A') + 10);\n        else i += (p[len] - '0');\n        len++;\n    }\n    return i;\n}\nNK_API struct nk_color\nnk_rgb_factor(struct nk_color col, float factor)\n{\n    if (factor == 1.0f)\n        return col;\n    col.r = (nk_byte)(col.r * factor);\n    col.g = (nk_byte)(col.g * factor);\n    col.b = (nk_byte)(col.b * factor);\n    return col;\n}\nNK_API struct nk_color\nnk_rgba(int r, int g, int b, int a)\n{\n    struct nk_color ret;\n    ret.r = (nk_byte)NK_CLAMP(0, r, 255);\n    ret.g = (nk_byte)NK_CLAMP(0, g, 255);\n    ret.b = (nk_byte)NK_CLAMP(0, b, 255);\n    ret.a = (nk_byte)NK_CLAMP(0, a, 255);\n    return ret;\n}\nNK_API struct nk_color\nnk_rgb_hex(const char *rgb)\n{\n    struct nk_color col;\n    const char *c = rgb;\n    if (*c == '#') c++;\n    col.r = (nk_byte)nk_parse_hex(c, 2);\n    col.g = (nk_byte)nk_parse_hex(c+2, 2);\n    col.b = (nk_byte)nk_parse_hex(c+4, 2);\n    col.a = 255;\n    return col;\n}\nNK_API struct nk_color\nnk_rgba_hex(const char *rgb)\n{\n    struct nk_color col;\n    const char *c = rgb;\n    if (*c == '#') c++;\n    col.r = (nk_byte)nk_parse_hex(c, 2);\n    col.g = (nk_byte)nk_parse_hex(c+2, 2);\n    col.b = (nk_byte)nk_parse_hex(c+4, 2);\n    col.a = (nk_byte)nk_parse_hex(c+6, 2);\n    return col;\n}\nNK_API void\nnk_color_hex_rgba(char *output, struct nk_color col)\n{\n    #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i))\n    output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);\n    output[1] = (char)NK_TO_HEX((col.r & 0x0F));\n    output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);\n    output[3] = (char)NK_TO_HEX((col.g & 0x0F));\n    output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);\n    output[5] = (char)NK_TO_HEX((col.b & 0x0F));\n    output[6] = (char)NK_TO_HEX((col.a & 0xF0) >> 4);\n    output[7] = (char)NK_TO_HEX((col.a & 0x0F));\n    output[8] = '\\0';\n    #undef NK_TO_HEX\n}\nNK_API void\nnk_color_hex_rgb(char *output, struct nk_color col)\n{\n    #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i))\n    output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);\n    output[1] = (char)NK_TO_HEX((col.r & 0x0F));\n    output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);\n    output[3] = (char)NK_TO_HEX((col.g & 0x0F));\n    output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);\n    output[5] = (char)NK_TO_HEX((col.b & 0x0F));\n    output[6] = '\\0';\n    #undef NK_TO_HEX\n}\nNK_API struct nk_color\nnk_rgba_iv(const int *c)\n{\n    return nk_rgba(c[0], c[1], c[2], c[3]);\n}\nNK_API struct nk_color\nnk_rgba_bv(const nk_byte *c)\n{\n    return nk_rgba(c[0], c[1], c[2], c[3]);\n}\nNK_API struct nk_color\nnk_rgb(int r, int g, int b)\n{\n    struct nk_color ret;\n    ret.r = (nk_byte)NK_CLAMP(0, r, 255);\n    ret.g = (nk_byte)NK_CLAMP(0, g, 255);\n    ret.b = (nk_byte)NK_CLAMP(0, b, 255);\n    ret.a = (nk_byte)255;\n    return ret;\n}\nNK_API struct nk_color\nnk_rgb_iv(const int *c)\n{\n    return nk_rgb(c[0], c[1], c[2]);\n}\nNK_API struct nk_color\nnk_rgb_bv(const nk_byte* c)\n{\n    return nk_rgb(c[0], c[1], c[2]);\n}\nNK_API struct nk_color\nnk_rgba_u32(nk_uint in)\n{\n    struct nk_color ret;\n    ret.r = (in & 0xFF);\n    ret.g = ((in >> 8) & 0xFF);\n    ret.b = ((in >> 16) & 0xFF);\n    ret.a = (nk_byte)((in >> 24) & 0xFF);\n    return ret;\n}\nNK_API struct nk_color\nnk_rgba_f(float r, float g, float b, float a)\n{\n    struct nk_color ret;\n    ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);\n    ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);\n    ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);\n    ret.a = (nk_byte)(NK_SATURATE(a) * 255.0f);\n    return ret;\n}\nNK_API struct nk_color\nnk_rgba_fv(const float *c)\n{\n    return nk_rgba_f(c[0], c[1], c[2], c[3]);\n}\nNK_API struct nk_color\nnk_rgba_cf(struct nk_colorf c)\n{\n    return nk_rgba_f(c.r, c.g, c.b, c.a);\n}\nNK_API struct nk_color\nnk_rgb_f(float r, float g, float b)\n{\n    struct nk_color ret;\n    ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);\n    ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);\n    ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);\n    ret.a = 255;\n    return ret;\n}\nNK_API struct nk_color\nnk_rgb_fv(const float *c)\n{\n    return nk_rgb_f(c[0], c[1], c[2]);\n}\nNK_API struct nk_color\nnk_rgb_cf(struct nk_colorf c)\n{\n    return nk_rgb_f(c.r, c.g, c.b);\n}\nNK_API struct nk_color\nnk_hsv(int h, int s, int v)\n{\n    return nk_hsva(h, s, v, 255);\n}\nNK_API struct nk_color\nnk_hsv_iv(const int *c)\n{\n    return nk_hsv(c[0], c[1], c[2]);\n}\nNK_API struct nk_color\nnk_hsv_bv(const nk_byte *c)\n{\n    return nk_hsv(c[0], c[1], c[2]);\n}\nNK_API struct nk_color\nnk_hsv_f(float h, float s, float v)\n{\n    return nk_hsva_f(h, s, v, 1.0f);\n}\nNK_API struct nk_color\nnk_hsv_fv(const float *c)\n{\n    return nk_hsv_f(c[0], c[1], c[2]);\n}\nNK_API struct nk_color\nnk_hsva(int h, int s, int v, int a)\n{\n    float hf = ((float)NK_CLAMP(0, h, 255)) / 255.0f;\n    float sf = ((float)NK_CLAMP(0, s, 255)) / 255.0f;\n    float vf = ((float)NK_CLAMP(0, v, 255)) / 255.0f;\n    float af = ((float)NK_CLAMP(0, a, 255)) / 255.0f;\n    return nk_hsva_f(hf, sf, vf, af);\n}\nNK_API struct nk_color\nnk_hsva_iv(const int *c)\n{\n    return nk_hsva(c[0], c[1], c[2], c[3]);\n}\nNK_API struct nk_color\nnk_hsva_bv(const nk_byte *c)\n{\n    return nk_hsva(c[0], c[1], c[2], c[3]);\n}\nNK_API struct nk_colorf\nnk_hsva_colorf(float h, float s, float v, float a)\n{\n    int i;\n    float p, q, t, f;\n    struct nk_colorf out = {0,0,0,0};\n    if (s <= 0.0f) {\n        out.r = v; out.g = v; out.b = v; out.a = a;\n        return out;\n    }\n    h = h / (60.0f/360.0f);\n    i = (int)h;\n    f = h - (float)i;\n    p = v * (1.0f - s);\n    q = v * (1.0f - (s * f));\n    t = v * (1.0f - s * (1.0f - f));\n\n    switch (i) {\n    case 0: default: out.r = v; out.g = t; out.b = p; break;\n    case 1: out.r = q; out.g = v; out.b = p; break;\n    case 2: out.r = p; out.g = v; out.b = t; break;\n    case 3: out.r = p; out.g = q; out.b = v; break;\n    case 4: out.r = t; out.g = p; out.b = v; break;\n    case 5: out.r = v; out.g = p; out.b = q; break;}\n    out.a = a;\n    return out;\n}\nNK_API struct nk_colorf\nnk_hsva_colorfv(const float *c)\n{\n    return nk_hsva_colorf(c[0], c[1], c[2], c[3]);\n}\nNK_API struct nk_color\nnk_hsva_f(float h, float s, float v, float a)\n{\n    struct nk_colorf c = nk_hsva_colorf(h, s, v, a);\n    return nk_rgba_f(c.r, c.g, c.b, c.a);\n}\nNK_API struct nk_color\nnk_hsva_fv(const float *c)\n{\n    return nk_hsva_f(c[0], c[1], c[2], c[3]);\n}\nNK_API nk_uint\nnk_color_u32(struct nk_color in)\n{\n    nk_uint out = (nk_uint)in.r;\n    out |= ((nk_uint)in.g << 8);\n    out |= ((nk_uint)in.b << 16);\n    out |= ((nk_uint)in.a << 24);\n    return out;\n}\nNK_API void\nnk_color_f(float *r, float *g, float *b, float *a, struct nk_color in)\n{\n    NK_STORAGE const float s = 1.0f/255.0f;\n    *r = (float)in.r * s;\n    *g = (float)in.g * s;\n    *b = (float)in.b * s;\n    *a = (float)in.a * s;\n}\nNK_API void\nnk_color_fv(float *c, struct nk_color in)\n{\n    nk_color_f(&c[0], &c[1], &c[2], &c[3], in);\n}\nNK_API struct nk_colorf\nnk_color_cf(struct nk_color in)\n{\n    struct nk_colorf o;\n    nk_color_f(&o.r, &o.g, &o.b, &o.a, in);\n    return o;\n}\nNK_API void\nnk_color_d(double *r, double *g, double *b, double *a, struct nk_color in)\n{\n    NK_STORAGE const double s = 1.0/255.0;\n    *r = (double)in.r * s;\n    *g = (double)in.g * s;\n    *b = (double)in.b * s;\n    *a = (double)in.a * s;\n}\nNK_API void\nnk_color_dv(double *c, struct nk_color in)\n{\n    nk_color_d(&c[0], &c[1], &c[2], &c[3], in);\n}\nNK_API void\nnk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color in)\n{\n    float a;\n    nk_color_hsva_f(out_h, out_s, out_v, &a, in);\n}\nNK_API void\nnk_color_hsv_fv(float *out, struct nk_color in)\n{\n    float a;\n    nk_color_hsva_f(&out[0], &out[1], &out[2], &a, in);\n}\nNK_API void\nnk_colorf_hsva_f(float *out_h, float *out_s,\n    float *out_v, float *out_a, struct nk_colorf in)\n{\n    float chroma;\n    float K = 0.0f;\n    if (in.g < in.b) {\n        const float t = in.g; in.g = in.b; in.b = t;\n        K = -1.f;\n    }\n    if (in.r < in.g) {\n        const float t = in.r; in.r = in.g; in.g = t;\n        K = -2.f/6.0f - K;\n    }\n    chroma = in.r - ((in.g < in.b) ? in.g: in.b);\n    *out_h = NK_ABS(K + (in.g - in.b)/(6.0f * chroma + 1e-20f));\n    *out_s = chroma / (in.r + 1e-20f);\n    *out_v = in.r;\n    *out_a = in.a;\n\n}\nNK_API void\nnk_colorf_hsva_fv(float *hsva, struct nk_colorf in)\n{\n    nk_colorf_hsva_f(&hsva[0], &hsva[1], &hsva[2], &hsva[3], in);\n}\nNK_API void\nnk_color_hsva_f(float *out_h, float *out_s,\n    float *out_v, float *out_a, struct nk_color in)\n{\n    struct nk_colorf col;\n    nk_color_f(&col.r,&col.g,&col.b,&col.a, in);\n    nk_colorf_hsva_f(out_h, out_s, out_v, out_a, col);\n}\nNK_API void\nnk_color_hsva_fv(float *out, struct nk_color in)\n{\n    nk_color_hsva_f(&out[0], &out[1], &out[2], &out[3], in);\n}\nNK_API void\nnk_color_hsva_i(int *out_h, int *out_s, int *out_v,\n                int *out_a, struct nk_color in)\n{\n    float h,s,v,a;\n    nk_color_hsva_f(&h, &s, &v, &a, in);\n    *out_h = (nk_byte)(h * 255.0f);\n    *out_s = (nk_byte)(s * 255.0f);\n    *out_v = (nk_byte)(v * 255.0f);\n    *out_a = (nk_byte)(a * 255.0f);\n}\nNK_API void\nnk_color_hsva_iv(int *out, struct nk_color in)\n{\n    nk_color_hsva_i(&out[0], &out[1], &out[2], &out[3], in);\n}\nNK_API void\nnk_color_hsva_bv(nk_byte *out, struct nk_color in)\n{\n    int tmp[4];\n    nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);\n    out[0] = (nk_byte)tmp[0];\n    out[1] = (nk_byte)tmp[1];\n    out[2] = (nk_byte)tmp[2];\n    out[3] = (nk_byte)tmp[3];\n}\nNK_API void\nnk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color in)\n{\n    int tmp[4];\n    nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);\n    *h = (nk_byte)tmp[0];\n    *s = (nk_byte)tmp[1];\n    *v = (nk_byte)tmp[2];\n    *a = (nk_byte)tmp[3];\n}\nNK_API void\nnk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color in)\n{\n    int a;\n    nk_color_hsva_i(out_h, out_s, out_v, &a, in);\n}\nNK_API void\nnk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color in)\n{\n    int tmp[4];\n    nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);\n    *out_h = (nk_byte)tmp[0];\n    *out_s = (nk_byte)tmp[1];\n    *out_v = (nk_byte)tmp[2];\n}\nNK_API void\nnk_color_hsv_iv(int *out, struct nk_color in)\n{\n    nk_color_hsv_i(&out[0], &out[1], &out[2], in);\n}\nNK_API void\nnk_color_hsv_bv(nk_byte *out, struct nk_color in)\n{\n    int tmp[4];\n    nk_color_hsv_i(&tmp[0], &tmp[1], &tmp[2], in);\n    out[0] = (nk_byte)tmp[0];\n    out[1] = (nk_byte)tmp[1];\n    out[2] = (nk_byte)tmp[2];\n}\n\n\n\n\n/* ===============================================================\n *\n *                              UTF-8\n *\n * ===============================================================*/\nNK_GLOBAL const nk_byte nk_utfbyte[NK_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0};\nNK_GLOBAL const nk_byte nk_utfmask[NK_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};\nNK_GLOBAL const nk_uint nk_utfmin[NK_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x10000};\nNK_GLOBAL const nk_uint nk_utfmax[NK_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};\n\nNK_INTERN int\nnk_utf_validate(nk_rune *u, int i)\n{\n    NK_ASSERT(u);\n    if (!u) return 0;\n    if (!NK_BETWEEN(*u, nk_utfmin[i], nk_utfmax[i]) ||\n         NK_BETWEEN(*u, 0xD800, 0xDFFF))\n            *u = NK_UTF_INVALID;\n    for (i = 1; *u > nk_utfmax[i]; ++i);\n    return i;\n}\nNK_INTERN nk_rune\nnk_utf_decode_byte(char c, int *i)\n{\n    NK_ASSERT(i);\n    if (!i) return 0;\n    for(*i = 0; *i < (int)NK_LEN(nk_utfmask); ++(*i)) {\n        if (((nk_byte)c & nk_utfmask[*i]) == nk_utfbyte[*i])\n            return (nk_byte)(c & ~nk_utfmask[*i]);\n    }\n    return 0;\n}\nNK_API int\nnk_utf_decode(const char *c, nk_rune *u, int clen)\n{\n    int i, j, len, type=0;\n    nk_rune udecoded;\n\n    NK_ASSERT(c);\n    NK_ASSERT(u);\n\n    if (!c || !u) return 0;\n    if (!clen) return 0;\n    *u = NK_UTF_INVALID;\n\n    udecoded = nk_utf_decode_byte(c[0], &len);\n    if (!NK_BETWEEN(len, 1, NK_UTF_SIZE+1)) /* +1 because NK_BETWEEN uses strict upper bound ((a) <= (x) && (x) < (b)) */\n        return 1;\n\n    for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {\n        udecoded = (udecoded << 6) | nk_utf_decode_byte(c[i], &type);\n        if (type != 0)\n            return j;\n    }\n    if (j < len)\n        return 0;\n    *u = udecoded;\n    nk_utf_validate(u, len);\n    return len;\n}\nNK_INTERN char\nnk_utf_encode_byte(nk_rune u, int i)\n{\n    return (char)((nk_utfbyte[i]) | ((nk_byte)u & ~nk_utfmask[i]));\n}\nNK_API int\nnk_utf_encode(nk_rune u, char *c, int clen)\n{\n    int len, i;\n    len = nk_utf_validate(&u, 0);\n    if (clen < len || !len || len > NK_UTF_SIZE)\n        return 0;\n\n    for (i = len - 1; i != 0; --i) {\n        c[i] = nk_utf_encode_byte(u, 0);\n        u >>= 6;\n    }\n    c[0] = nk_utf_encode_byte(u, len);\n    return len;\n}\nNK_API int\nnk_utf_len(const char *str, int len)\n{\n    const char *text;\n    int glyphs = 0;\n    int text_len;\n    int glyph_len;\n    int src_len = 0;\n    nk_rune unicode;\n\n    NK_ASSERT(str);\n    if (!str || !len) return 0;\n\n    text = str;\n    text_len = len;\n    glyph_len = nk_utf_decode(text, &unicode, text_len);\n    while (glyph_len && src_len < len) {\n        glyphs++;\n        src_len = src_len + glyph_len;\n        glyph_len = nk_utf_decode(text + src_len, &unicode, text_len - src_len);\n    }\n    return glyphs;\n}\nNK_API const char*\nnk_utf_at(const char *buffer, int length, int index,\n    nk_rune *unicode, int *len)\n{\n    int i = 0;\n    int src_len = 0;\n    int glyph_len = 0;\n    const char *text;\n    int text_len;\n\n    NK_ASSERT(buffer);\n    NK_ASSERT(unicode);\n    NK_ASSERT(len);\n\n    if (!buffer || !unicode || !len) return 0;\n    if (index < 0) {\n        *unicode = NK_UTF_INVALID;\n        *len = 0;\n        return 0;\n    }\n\n    text = buffer;\n    text_len = length;\n    glyph_len = nk_utf_decode(text, unicode, text_len);\n    while (glyph_len) {\n        if (i == index) {\n            *len = glyph_len;\n            break;\n        }\n\n        i++;\n        src_len = src_len + glyph_len;\n        glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);\n    }\n    if (i != index) return 0;\n    return buffer + src_len;\n}\n\n\n\n\n\n/* ==============================================================\n *\n *                          BUFFER\n *\n * ===============================================================*/\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_LIB void*\nnk_malloc(nk_handle unused, void *old,nk_size size)\n{\n    NK_UNUSED(unused);\n    NK_UNUSED(old);\n    return malloc(size);\n}\nNK_LIB void\nnk_mfree(nk_handle unused, void *ptr)\n{\n    NK_UNUSED(unused);\n    free(ptr);\n}\nNK_API void\nnk_buffer_init_default(struct nk_buffer *buffer)\n{\n    struct nk_allocator alloc;\n    alloc.userdata.ptr = 0;\n    alloc.alloc = nk_malloc;\n    alloc.free = nk_mfree;\n    nk_buffer_init(buffer, &alloc, NK_BUFFER_DEFAULT_INITIAL_SIZE);\n}\n#endif\n\nNK_API void\nnk_buffer_init(struct nk_buffer *b, const struct nk_allocator *a,\n    nk_size initial_size)\n{\n    NK_ASSERT(b);\n    NK_ASSERT(a);\n    NK_ASSERT(initial_size);\n    if (!b || !a || !initial_size) return;\n\n    nk_zero(b, sizeof(*b));\n    b->type = NK_BUFFER_DYNAMIC;\n    b->memory.ptr = a->alloc(a->userdata,0, initial_size);\n    b->memory.size = initial_size;\n    b->size = initial_size;\n    b->grow_factor = 2.0f;\n    b->pool = *a;\n}\nNK_API void\nnk_buffer_init_fixed(struct nk_buffer *b, void *m, nk_size size)\n{\n    NK_ASSERT(b);\n    NK_ASSERT(m);\n    NK_ASSERT(size);\n    if (!b || !m || !size) return;\n\n    nk_zero(b, sizeof(*b));\n    b->type = NK_BUFFER_FIXED;\n    b->memory.ptr = m;\n    b->memory.size = size;\n    b->size = size;\n}\nNK_LIB void*\nnk_buffer_align(void *unaligned,\n    nk_size align, nk_size *alignment,\n    enum nk_buffer_allocation_type type)\n{\n    void *memory = 0;\n    switch (type) {\n    default:\n    case NK_BUFFER_MAX:\n    case NK_BUFFER_FRONT:\n        if (align) {\n            memory = NK_ALIGN_PTR(unaligned, align);\n            *alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);\n        } else {\n            memory = unaligned;\n            *alignment = 0;\n        }\n        break;\n    case NK_BUFFER_BACK:\n        if (align) {\n            memory = NK_ALIGN_PTR_BACK(unaligned, align);\n            *alignment = (nk_size)((nk_byte*)unaligned - (nk_byte*)memory);\n        } else {\n            memory = unaligned;\n            *alignment = 0;\n        }\n        break;\n    }\n    return memory;\n}\nNK_LIB void*\nnk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size)\n{\n    void *temp;\n    nk_size buffer_size;\n\n    NK_ASSERT(b);\n    NK_ASSERT(size);\n    if (!b || !size || !b->pool.alloc || !b->pool.free)\n        return 0;\n\n    buffer_size = b->memory.size;\n    temp = b->pool.alloc(b->pool.userdata, b->memory.ptr, capacity);\n    NK_ASSERT(temp);\n    if (!temp) return 0;\n\n    *size = capacity;\n    if (temp != b->memory.ptr) {\n        NK_MEMCPY(temp, b->memory.ptr, buffer_size);\n        b->pool.free(b->pool.userdata, b->memory.ptr);\n    }\n\n    if (b->size == buffer_size) {\n        /* no back buffer so just set correct size */\n        b->size = capacity;\n        return temp;\n    } else {\n        /* copy back buffer to the end of the new buffer */\n        void *dst, *src;\n        nk_size back_size;\n        back_size = buffer_size - b->size;\n        dst = nk_ptr_add(void, temp, capacity - back_size);\n        src = nk_ptr_add(void, temp, b->size);\n        NK_MEMCPY(dst, src, back_size);\n        b->size = capacity - back_size;\n    }\n    return temp;\n}\nNK_LIB void*\nnk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type,\n    nk_size size, nk_size align)\n{\n    int full;\n    nk_size alignment;\n    void *unaligned;\n    void *memory;\n\n    NK_ASSERT(b);\n    NK_ASSERT(size);\n    if (!b || !size) return 0;\n    b->needed += size;\n\n    /* calculate total size with needed alignment + size */\n    if (type == NK_BUFFER_FRONT)\n        unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated);\n    else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size);\n    memory = nk_buffer_align(unaligned, align, &alignment, type);\n\n    /* check if buffer has enough memory*/\n    if (type == NK_BUFFER_FRONT)\n        full = ((b->allocated + size + alignment) > b->size);\n    else full = ((b->size - NK_MIN(b->size,(size + alignment))) <= b->allocated);\n\n    if (full) {\n        nk_size capacity;\n        if (b->type != NK_BUFFER_DYNAMIC)\n            return 0;\n        NK_ASSERT(b->pool.alloc && b->pool.free);\n        if (b->type != NK_BUFFER_DYNAMIC || !b->pool.alloc || !b->pool.free)\n            return 0;\n\n        /* buffer is full so allocate bigger buffer if dynamic */\n        capacity = (nk_size)((float)b->memory.size * b->grow_factor);\n        capacity = NK_MAX(capacity, nk_round_up_pow2((nk_uint)(b->allocated + size)));\n        b->memory.ptr = nk_buffer_realloc(b, capacity, &b->memory.size);\n        if (!b->memory.ptr) return 0;\n\n        /* align newly allocated pointer */\n        if (type == NK_BUFFER_FRONT)\n            unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated);\n        else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size);\n        memory = nk_buffer_align(unaligned, align, &alignment, type);\n    }\n    if (type == NK_BUFFER_FRONT)\n        b->allocated += size + alignment;\n    else b->size -= (size + alignment);\n    b->needed += alignment;\n    b->calls++;\n    return memory;\n}\nNK_API void\nnk_buffer_push(struct nk_buffer *b, enum nk_buffer_allocation_type type,\n    const void *memory, nk_size size, nk_size align)\n{\n    void *mem = nk_buffer_alloc(b, type, size, align);\n    if (!mem) return;\n    NK_MEMCPY(mem, memory, size);\n}\nNK_API void\nnk_buffer_mark(struct nk_buffer *buffer, enum nk_buffer_allocation_type type)\n{\n    NK_ASSERT(buffer);\n    if (!buffer) return;\n    buffer->marker[type].active = nk_true;\n    if (type == NK_BUFFER_BACK)\n        buffer->marker[type].offset = buffer->size;\n    else buffer->marker[type].offset = buffer->allocated;\n}\nNK_API void\nnk_buffer_reset(struct nk_buffer *buffer, enum nk_buffer_allocation_type type)\n{\n    NK_ASSERT(buffer);\n    if (!buffer) return;\n    if (type == NK_BUFFER_BACK) {\n        /* reset back buffer either back to marker or empty */\n        buffer->needed -= (buffer->memory.size - buffer->marker[type].offset);\n        if (buffer->marker[type].active)\n            buffer->size = buffer->marker[type].offset;\n        else buffer->size = buffer->memory.size;\n        buffer->marker[type].active = nk_false;\n    } else {\n        /* reset front buffer either back to back marker or empty */\n        buffer->needed -= (buffer->allocated - buffer->marker[type].offset);\n        if (buffer->marker[type].active)\n            buffer->allocated = buffer->marker[type].offset;\n        else buffer->allocated = 0;\n        buffer->marker[type].active = nk_false;\n    }\n}\nNK_API void\nnk_buffer_clear(struct nk_buffer *b)\n{\n    NK_ASSERT(b);\n    if (!b) return;\n    b->allocated = 0;\n    b->size = b->memory.size;\n    b->calls = 0;\n    b->needed = 0;\n}\nNK_API void\nnk_buffer_free(struct nk_buffer *b)\n{\n    NK_ASSERT(b);\n    if (!b || !b->memory.ptr) return;\n    if (b->type == NK_BUFFER_FIXED) return;\n    if (!b->pool.free) return;\n    NK_ASSERT(b->pool.free);\n    b->pool.free(b->pool.userdata, b->memory.ptr);\n}\nNK_API void\nnk_buffer_info(struct nk_memory_status *s, const struct nk_buffer *b)\n{\n    NK_ASSERT(b);\n    NK_ASSERT(s);\n    if (!s || !b) return;\n    s->allocated = b->allocated;\n    s->size =  b->memory.size;\n    s->needed = b->needed;\n    s->memory = b->memory.ptr;\n    s->calls = b->calls;\n}\nNK_API void*\nnk_buffer_memory(struct nk_buffer *buffer)\n{\n    NK_ASSERT(buffer);\n    if (!buffer) return 0;\n    return buffer->memory.ptr;\n}\nNK_API const void*\nnk_buffer_memory_const(const struct nk_buffer *buffer)\n{\n    NK_ASSERT(buffer);\n    if (!buffer) return 0;\n    return buffer->memory.ptr;\n}\nNK_API nk_size\nnk_buffer_total(const struct nk_buffer *buffer)\n{\n    NK_ASSERT(buffer);\n    if (!buffer) return 0;\n    return buffer->memory.size;\n}\n\n\n\n\n/* ===============================================================\n *\n *                              STRING\n *\n * ===============================================================*/\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void\nnk_str_init_default(struct nk_str *str)\n{\n    struct nk_allocator alloc;\n    alloc.userdata.ptr = 0;\n    alloc.alloc = nk_malloc;\n    alloc.free = nk_mfree;\n    nk_buffer_init(&str->buffer, &alloc, 32);\n    str->len = 0;\n}\n#endif\n\nNK_API void\nnk_str_init(struct nk_str *str, const struct nk_allocator *alloc, nk_size size)\n{\n    nk_buffer_init(&str->buffer, alloc, size);\n    str->len = 0;\n}\nNK_API void\nnk_str_init_fixed(struct nk_str *str, void *memory, nk_size size)\n{\n    nk_buffer_init_fixed(&str->buffer, memory, size);\n    str->len = 0;\n}\nNK_API int\nnk_str_append_text_char(struct nk_str *s, const char *str, int len)\n{\n    char *mem;\n    NK_ASSERT(s);\n    NK_ASSERT(str);\n    if (!s || !str || !len) return 0;\n    mem = (char*)nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0);\n    if (!mem) return 0;\n    NK_MEMCPY(mem, str, (nk_size)len * sizeof(char));\n    s->len += nk_utf_len(str, len);\n    return len;\n}\nNK_API int\nnk_str_append_str_char(struct nk_str *s, const char *str)\n{\n    return nk_str_append_text_char(s, str, nk_strlen(str));\n}\nNK_API int\nnk_str_append_text_utf8(struct nk_str *str, const char *text, int len)\n{\n    int i = 0;\n    int byte_len = 0;\n    nk_rune unicode;\n    if (!str || !text || !len) return 0;\n    for (i = 0; i < len; ++i)\n        byte_len += nk_utf_decode(text+byte_len, &unicode, 4);\n    nk_str_append_text_char(str, text, byte_len);\n    return len;\n}\nNK_API int\nnk_str_append_str_utf8(struct nk_str *str, const char *text)\n{\n    int byte_len = 0;\n    int num_runes = 0;\n    int glyph_len = 0;\n    nk_rune unicode;\n    if (!str || !text) return 0;\n\n    glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4);\n    while (unicode != '\\0' && glyph_len) {\n        glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);\n        byte_len += glyph_len;\n        num_runes++;\n    }\n    nk_str_append_text_char(str, text, byte_len);\n    return num_runes;\n}\nNK_API int\nnk_str_append_text_runes(struct nk_str *str, const nk_rune *text, int len)\n{\n    int i = 0;\n    int byte_len = 0;\n    nk_glyph glyph;\n\n    NK_ASSERT(str);\n    if (!str || !text || !len) return 0;\n    for (i = 0; i < len; ++i) {\n        byte_len = nk_utf_encode(text[i], glyph, NK_UTF_SIZE);\n        if (!byte_len) break;\n        nk_str_append_text_char(str, glyph, byte_len);\n    }\n    return len;\n}\nNK_API int\nnk_str_append_str_runes(struct nk_str *str, const nk_rune *runes)\n{\n    int i = 0;\n    nk_glyph glyph;\n    int byte_len;\n    NK_ASSERT(str);\n    if (!str || !runes) return 0;\n    while (runes[i] != '\\0') {\n        byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);\n        nk_str_append_text_char(str, glyph, byte_len);\n        i++;\n    }\n    return i;\n}\nNK_API int\nnk_str_insert_at_char(struct nk_str *s, int pos, const char *str, int len)\n{\n    int i;\n    void *mem;\n    char *src;\n    char *dst;\n\n    int copylen;\n    NK_ASSERT(s);\n    NK_ASSERT(str);\n    NK_ASSERT(len >= 0);\n    if (!s || !str || !len || (nk_size)pos > s->buffer.allocated) return 0;\n    if ((s->buffer.allocated + (nk_size)len >= s->buffer.memory.size) &&\n        (s->buffer.type == NK_BUFFER_FIXED)) return 0;\n\n    copylen = (int)s->buffer.allocated - pos;\n    if (!copylen) {\n        nk_str_append_text_char(s, str, len);\n        return 1;\n    }\n    mem = nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0);\n    if (!mem) return 0;\n\n    /* memmove */\n    NK_ASSERT(((int)pos + (int)len + ((int)copylen - 1)) >= 0);\n    NK_ASSERT(((int)pos + ((int)copylen - 1)) >= 0);\n    dst = nk_ptr_add(char, s->buffer.memory.ptr, pos + len + (copylen - 1));\n    src = nk_ptr_add(char, s->buffer.memory.ptr, pos + (copylen-1));\n    for (i = 0; i < copylen; ++i) *dst-- = *src--;\n    mem = nk_ptr_add(void, s->buffer.memory.ptr, pos);\n    NK_MEMCPY(mem, str, (nk_size)len * sizeof(char));\n    s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);\n    return 1;\n}\nNK_API int\nnk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len)\n{\n    int glyph_len;\n    nk_rune unicode;\n    const char *begin;\n    const char *buffer;\n\n    NK_ASSERT(str);\n    NK_ASSERT(cstr);\n    NK_ASSERT(len);\n    if (!str || !cstr || !len) return 0;\n    begin = nk_str_at_rune(str, pos, &unicode, &glyph_len);\n    if (!str->len)\n        return nk_str_append_text_char(str, cstr, len);\n    buffer = nk_str_get_const(str);\n    if (!begin) return 0;\n    return nk_str_insert_at_char(str, (int)(begin - buffer), cstr, len);\n}\nNK_API int\nnk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len)\n{\n    return nk_str_insert_text_utf8(str, pos, text, len);\n}\nNK_API int\nnk_str_insert_str_char(struct nk_str *str, int pos, const char *text)\n{\n    return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text));\n}\nNK_API int\nnk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len)\n{\n    int i = 0;\n    int byte_len = 0;\n    nk_rune unicode;\n\n    NK_ASSERT(str);\n    NK_ASSERT(text);\n    if (!str || !text || !len) return 0;\n    for (i = 0; i < len; ++i)\n        byte_len += nk_utf_decode(text+byte_len, &unicode, 4);\n    nk_str_insert_at_rune(str, pos, text, byte_len);\n    return len;\n}\nNK_API int\nnk_str_insert_str_utf8(struct nk_str *str, int pos, const char *text)\n{\n    int byte_len = 0;\n    int num_runes = 0;\n    int glyph_len = 0;\n    nk_rune unicode;\n    if (!str || !text) return 0;\n\n    glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4);\n    while (unicode != '\\0' && glyph_len) {\n        glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);\n        byte_len += glyph_len;\n        num_runes++;\n    }\n    nk_str_insert_at_rune(str, pos, text, byte_len);\n    return num_runes;\n}\nNK_API int\nnk_str_insert_text_runes(struct nk_str *str, int pos, const nk_rune *runes, int len)\n{\n    int i = 0;\n    int byte_len = 0;\n    nk_glyph glyph;\n\n    NK_ASSERT(str);\n    if (!str || !runes || !len) return 0;\n    for (i = 0; i < len; ++i) {\n        byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);\n        if (!byte_len) break;\n        nk_str_insert_at_rune(str, pos+i, glyph, byte_len);\n    }\n    return len;\n}\nNK_API int\nnk_str_insert_str_runes(struct nk_str *str, int pos, const nk_rune *runes)\n{\n    int i = 0;\n    nk_glyph glyph;\n    int byte_len;\n    NK_ASSERT(str);\n    if (!str || !runes) return 0;\n    while (runes[i] != '\\0') {\n        byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);\n        nk_str_insert_at_rune(str, pos+i, glyph, byte_len);\n        i++;\n    }\n    return i;\n}\nNK_API void\nnk_str_remove_chars(struct nk_str *s, int len)\n{\n    NK_ASSERT(s);\n    NK_ASSERT(len >= 0);\n    if (!s || len < 0 || (nk_size)len > s->buffer.allocated) return;\n    NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0);\n    s->buffer.allocated -= (nk_size)len;\n    s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);\n}\nNK_API void\nnk_str_remove_runes(struct nk_str *str, int len)\n{\n    int index;\n    const char *begin;\n    const char *end;\n    nk_rune unicode;\n\n    NK_ASSERT(str);\n    NK_ASSERT(len >= 0);\n    if (!str || len < 0) return;\n    if (len >= str->len) {\n        str->len = 0;\n        return;\n    }\n\n    index = str->len - len;\n    begin = nk_str_at_rune(str, index, &unicode, &len);\n    end = (const char*)str->buffer.memory.ptr + str->buffer.allocated;\n    nk_str_remove_chars(str, (int)(end-begin)+1);\n}\nNK_API void\nnk_str_delete_chars(struct nk_str *s, int pos, int len)\n{\n    NK_ASSERT(s);\n    if (!s || !len || (nk_size)pos > s->buffer.allocated ||\n        (nk_size)(pos + len) > s->buffer.allocated) return;\n\n    if ((nk_size)(pos + len) < s->buffer.allocated) {\n        /* memmove */\n        char *dst = nk_ptr_add(char, s->buffer.memory.ptr, pos);\n        char *src = nk_ptr_add(char, s->buffer.memory.ptr, pos + len);\n        NK_MEMCPY(dst, src, s->buffer.allocated - (nk_size)(pos + len));\n        NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0);\n        s->buffer.allocated -= (nk_size)len;\n    } else nk_str_remove_chars(s, len);\n    s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);\n}\nNK_API void\nnk_str_delete_runes(struct nk_str *s, int pos, int len)\n{\n    char *temp;\n    nk_rune unicode;\n    char *begin;\n    char *end;\n    int unused;\n\n    NK_ASSERT(s);\n    NK_ASSERT(s->len >= pos + len);\n    if (s->len < pos + len)\n        len = NK_CLAMP(0, (s->len - pos), s->len);\n    if (!len) return;\n\n    temp = (char *)s->buffer.memory.ptr;\n    begin = nk_str_at_rune(s, pos, &unicode, &unused);\n    if (!begin) return;\n    s->buffer.memory.ptr = begin;\n    end = nk_str_at_rune(s, len, &unicode, &unused);\n    s->buffer.memory.ptr = temp;\n    if (!end) return;\n    nk_str_delete_chars(s, (int)(begin - temp), (int)(end - begin));\n}\nNK_API char*\nnk_str_at_char(struct nk_str *s, int pos)\n{\n    NK_ASSERT(s);\n    if (!s || pos > (int)s->buffer.allocated) return 0;\n    return nk_ptr_add(char, s->buffer.memory.ptr, pos);\n}\nNK_API char*\nnk_str_at_rune(struct nk_str *str, int pos, nk_rune *unicode, int *len)\n{\n    int i = 0;\n    int src_len = 0;\n    int glyph_len = 0;\n    char *text;\n    int text_len;\n\n    NK_ASSERT(str);\n    NK_ASSERT(unicode);\n    NK_ASSERT(len);\n\n    if (!str || !unicode || !len) return 0;\n    if (pos < 0) {\n        *unicode = 0;\n        *len = 0;\n        return 0;\n    }\n\n    text = (char*)str->buffer.memory.ptr;\n    text_len = (int)str->buffer.allocated;\n    glyph_len = nk_utf_decode(text, unicode, text_len);\n    while (glyph_len) {\n        if (i == pos) {\n            *len = glyph_len;\n            break;\n        }\n\n        i++;\n        src_len = src_len + glyph_len;\n        glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);\n    }\n    if (i != pos) return 0;\n    return text + src_len;\n}\nNK_API const char*\nnk_str_at_char_const(const struct nk_str *s, int pos)\n{\n    NK_ASSERT(s);\n    if (!s || pos > (int)s->buffer.allocated) return 0;\n    return nk_ptr_add(char, s->buffer.memory.ptr, pos);\n}\nNK_API const char*\nnk_str_at_const(const struct nk_str *str, int pos, nk_rune *unicode, int *len)\n{\n    int i = 0;\n    int src_len = 0;\n    int glyph_len = 0;\n    char *text;\n    int text_len;\n\n    NK_ASSERT(str);\n    NK_ASSERT(unicode);\n    NK_ASSERT(len);\n\n    if (!str || !unicode || !len) return 0;\n    if (pos < 0) {\n        *unicode = 0;\n        *len = 0;\n        return 0;\n    }\n\n    text = (char*)str->buffer.memory.ptr;\n    text_len = (int)str->buffer.allocated;\n    glyph_len = nk_utf_decode(text, unicode, text_len);\n    while (glyph_len) {\n        if (i == pos) {\n            *len = glyph_len;\n            break;\n        }\n\n        i++;\n        src_len = src_len + glyph_len;\n        glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);\n    }\n    if (i != pos) return 0;\n    return text + src_len;\n}\nNK_API nk_rune\nnk_str_rune_at(const struct nk_str *str, int pos)\n{\n    int len;\n    nk_rune unicode = 0;\n    nk_str_at_const(str, pos, &unicode, &len);\n    return unicode;\n}\nNK_API char*\nnk_str_get(struct nk_str *s)\n{\n    NK_ASSERT(s);\n    if (!s || !s->len || !s->buffer.allocated) return 0;\n    return (char*)s->buffer.memory.ptr;\n}\nNK_API const char*\nnk_str_get_const(const struct nk_str *s)\n{\n    NK_ASSERT(s);\n    if (!s || !s->len || !s->buffer.allocated) return 0;\n    return (const char*)s->buffer.memory.ptr;\n}\nNK_API int\nnk_str_len(const struct nk_str *s)\n{\n    NK_ASSERT(s);\n    if (!s || !s->len || !s->buffer.allocated) return 0;\n    return s->len;\n}\nNK_API int\nnk_str_len_char(const struct nk_str *s)\n{\n    NK_ASSERT(s);\n    if (!s || !s->len || !s->buffer.allocated) return 0;\n    return (int)s->buffer.allocated;\n}\nNK_API void\nnk_str_clear(struct nk_str *str)\n{\n    NK_ASSERT(str);\n    nk_buffer_clear(&str->buffer);\n    str->len = 0;\n}\nNK_API void\nnk_str_free(struct nk_str *str)\n{\n    NK_ASSERT(str);\n    nk_buffer_free(&str->buffer);\n    str->len = 0;\n}\n\n\n\n\n/* ==============================================================\n *\n *                          DRAW\n *\n * ===============================================================*/\nNK_LIB void\nnk_command_buffer_init(struct nk_command_buffer *cb,\n    struct nk_buffer *b, enum nk_command_clipping clip)\n{\n    NK_ASSERT(cb);\n    NK_ASSERT(b);\n    if (!cb || !b) return;\n    cb->base = b;\n    cb->use_clipping = (int)clip;\n    cb->begin = b->allocated;\n    cb->end = b->allocated;\n    cb->last = b->allocated;\n}\nNK_LIB void\nnk_command_buffer_reset(struct nk_command_buffer *b)\n{\n    NK_ASSERT(b);\n    if (!b) return;\n    b->begin = 0;\n    b->end = 0;\n    b->last = 0;\n    b->clip = nk_null_rect;\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    b->userdata.ptr = 0;\n#endif\n}\nNK_LIB void*\nnk_command_buffer_push(struct nk_command_buffer* b,\n    enum nk_command_type t, nk_size size)\n{\n    NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_command);\n    struct nk_command *cmd;\n    nk_size alignment;\n    void *unaligned;\n    void *memory;\n\n    NK_ASSERT(b);\n    NK_ASSERT(b->base);\n    if (!b) return 0;\n    cmd = (struct nk_command*)nk_buffer_alloc(b->base,NK_BUFFER_FRONT,size,align);\n    if (!cmd) return 0;\n\n    /* make sure the offset to the next command is aligned */\n    b->last = (nk_size)((nk_byte*)cmd - (nk_byte*)b->base->memory.ptr);\n    unaligned = (nk_byte*)cmd + size;\n    memory = NK_ALIGN_PTR(unaligned, align);\n    alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);\n#ifdef NK_ZERO_COMMAND_MEMORY\n    NK_MEMSET(cmd, 0, size + alignment);\n#endif\n\n    cmd->type = t;\n    cmd->next = b->base->allocated + alignment;\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    cmd->userdata = b->userdata;\n#endif\n    b->end = cmd->next;\n    return cmd;\n}\nNK_API void\nnk_push_scissor(struct nk_command_buffer *b, struct nk_rect r)\n{\n    struct nk_command_scissor *cmd;\n    NK_ASSERT(b);\n    if (!b) return;\n\n    b->clip.x = r.x;\n    b->clip.y = r.y;\n    b->clip.w = r.w;\n    b->clip.h = r.h;\n    cmd = (struct nk_command_scissor*)\n        nk_command_buffer_push(b, NK_COMMAND_SCISSOR, sizeof(*cmd));\n\n    if (!cmd) return;\n    cmd->x = (short)r.x;\n    cmd->y = (short)r.y;\n    cmd->w = (unsigned short)NK_MAX(0, r.w);\n    cmd->h = (unsigned short)NK_MAX(0, r.h);\n}\nNK_API void\nnk_stroke_line(struct nk_command_buffer *b, float x0, float y0,\n    float x1, float y1, float line_thickness, struct nk_color c)\n{\n    struct nk_command_line *cmd;\n    NK_ASSERT(b);\n    if (!b || line_thickness <= 0) return;\n    cmd = (struct nk_command_line*)\n        nk_command_buffer_push(b, NK_COMMAND_LINE, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->begin.x = (short)x0;\n    cmd->begin.y = (short)y0;\n    cmd->end.x = (short)x1;\n    cmd->end.y = (short)y1;\n    cmd->color = c;\n}\nNK_API void\nnk_stroke_curve(struct nk_command_buffer *b, float ax, float ay,\n    float ctrl0x, float ctrl0y, float ctrl1x, float ctrl1y,\n    float bx, float by, float line_thickness, struct nk_color col)\n{\n    struct nk_command_curve *cmd;\n    NK_ASSERT(b);\n    if (!b || col.a == 0 || line_thickness <= 0) return;\n\n    cmd = (struct nk_command_curve*)\n        nk_command_buffer_push(b, NK_COMMAND_CURVE, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->begin.x = (short)ax;\n    cmd->begin.y = (short)ay;\n    cmd->ctrl[0].x = (short)ctrl0x;\n    cmd->ctrl[0].y = (short)ctrl0y;\n    cmd->ctrl[1].x = (short)ctrl1x;\n    cmd->ctrl[1].y = (short)ctrl1y;\n    cmd->end.x = (short)bx;\n    cmd->end.y = (short)by;\n    cmd->color = col;\n}\nNK_API void\nnk_stroke_rect(struct nk_command_buffer *b, struct nk_rect rect,\n    float rounding, float line_thickness, struct nk_color c)\n{\n    struct nk_command_rect *cmd;\n    NK_ASSERT(b);\n    if (!b || c.a == 0 || rect.w == 0 || rect.h == 0 || line_thickness <= 0) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,\n            clip->x, clip->y, clip->w, clip->h)) return;\n    }\n    cmd = (struct nk_command_rect*)\n        nk_command_buffer_push(b, NK_COMMAND_RECT, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->rounding = (unsigned short)rounding;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->x = (short)rect.x;\n    cmd->y = (short)rect.y;\n    cmd->w = (unsigned short)NK_MAX(0, rect.w);\n    cmd->h = (unsigned short)NK_MAX(0, rect.h);\n    cmd->color = c;\n}\nNK_API void\nnk_fill_rect(struct nk_command_buffer *b, struct nk_rect rect,\n    float rounding, struct nk_color c)\n{\n    struct nk_command_rect_filled *cmd;\n    NK_ASSERT(b);\n    if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,\n            clip->x, clip->y, clip->w, clip->h)) return;\n    }\n\n    cmd = (struct nk_command_rect_filled*)\n        nk_command_buffer_push(b, NK_COMMAND_RECT_FILLED, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->rounding = (unsigned short)rounding;\n    cmd->x = (short)rect.x;\n    cmd->y = (short)rect.y;\n    cmd->w = (unsigned short)NK_MAX(0, rect.w);\n    cmd->h = (unsigned short)NK_MAX(0, rect.h);\n    cmd->color = c;\n}\nNK_API void\nnk_fill_rect_multi_color(struct nk_command_buffer *b, struct nk_rect rect,\n    struct nk_color left, struct nk_color top, struct nk_color right,\n    struct nk_color bottom)\n{\n    struct nk_command_rect_multi_color *cmd;\n    NK_ASSERT(b);\n    if (!b || rect.w == 0 || rect.h == 0) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,\n            clip->x, clip->y, clip->w, clip->h)) return;\n    }\n\n    cmd = (struct nk_command_rect_multi_color*)\n        nk_command_buffer_push(b, NK_COMMAND_RECT_MULTI_COLOR, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->x = (short)rect.x;\n    cmd->y = (short)rect.y;\n    cmd->w = (unsigned short)NK_MAX(0, rect.w);\n    cmd->h = (unsigned short)NK_MAX(0, rect.h);\n    cmd->left = left;\n    cmd->top = top;\n    cmd->right = right;\n    cmd->bottom = bottom;\n}\nNK_API void\nnk_stroke_circle(struct nk_command_buffer *b, struct nk_rect r,\n    float line_thickness, struct nk_color c)\n{\n    struct nk_command_circle *cmd;\n    if (!b || r.w == 0 || r.h == 0 || line_thickness <= 0) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))\n            return;\n    }\n\n    cmd = (struct nk_command_circle*)\n        nk_command_buffer_push(b, NK_COMMAND_CIRCLE, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->x = (short)r.x;\n    cmd->y = (short)r.y;\n    cmd->w = (unsigned short)NK_MAX(r.w, 0);\n    cmd->h = (unsigned short)NK_MAX(r.h, 0);\n    cmd->color = c;\n}\nNK_API void\nnk_fill_circle(struct nk_command_buffer *b, struct nk_rect r, struct nk_color c)\n{\n    struct nk_command_circle_filled *cmd;\n    NK_ASSERT(b);\n    if (!b || c.a == 0 || r.w == 0 || r.h == 0) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))\n            return;\n    }\n\n    cmd = (struct nk_command_circle_filled*)\n        nk_command_buffer_push(b, NK_COMMAND_CIRCLE_FILLED, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->x = (short)r.x;\n    cmd->y = (short)r.y;\n    cmd->w = (unsigned short)NK_MAX(r.w, 0);\n    cmd->h = (unsigned short)NK_MAX(r.h, 0);\n    cmd->color = c;\n}\nNK_API void\nnk_stroke_arc(struct nk_command_buffer *b, float cx, float cy, float radius,\n    float a_min, float a_max, float line_thickness, struct nk_color c)\n{\n    struct nk_command_arc *cmd;\n    if (!b || c.a == 0 || line_thickness <= 0) return;\n    cmd = (struct nk_command_arc*)\n        nk_command_buffer_push(b, NK_COMMAND_ARC, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->cx = (short)cx;\n    cmd->cy = (short)cy;\n    cmd->r = (unsigned short)radius;\n    cmd->a[0] = a_min;\n    cmd->a[1] = a_max;\n    cmd->color = c;\n}\nNK_API void\nnk_fill_arc(struct nk_command_buffer *b, float cx, float cy, float radius,\n    float a_min, float a_max, struct nk_color c)\n{\n    struct nk_command_arc_filled *cmd;\n    NK_ASSERT(b);\n    if (!b || c.a == 0) return;\n    cmd = (struct nk_command_arc_filled*)\n        nk_command_buffer_push(b, NK_COMMAND_ARC_FILLED, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->cx = (short)cx;\n    cmd->cy = (short)cy;\n    cmd->r = (unsigned short)radius;\n    cmd->a[0] = a_min;\n    cmd->a[1] = a_max;\n    cmd->color = c;\n}\nNK_API void\nnk_stroke_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,\n    float y1, float x2, float y2, float line_thickness, struct nk_color c)\n{\n    struct nk_command_triangle *cmd;\n    NK_ASSERT(b);\n    if (!b || c.a == 0 || line_thickness <= 0) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&\n            !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&\n            !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))\n            return;\n    }\n\n    cmd = (struct nk_command_triangle*)\n        nk_command_buffer_push(b, NK_COMMAND_TRIANGLE, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->a.x = (short)x0;\n    cmd->a.y = (short)y0;\n    cmd->b.x = (short)x1;\n    cmd->b.y = (short)y1;\n    cmd->c.x = (short)x2;\n    cmd->c.y = (short)y2;\n    cmd->color = c;\n}\nNK_API void\nnk_fill_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,\n    float y1, float x2, float y2, struct nk_color c)\n{\n    struct nk_command_triangle_filled *cmd;\n    NK_ASSERT(b);\n    if (!b || c.a == 0) return;\n    if (!b) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&\n            !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&\n            !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))\n            return;\n    }\n\n    cmd = (struct nk_command_triangle_filled*)\n        nk_command_buffer_push(b, NK_COMMAND_TRIANGLE_FILLED, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->a.x = (short)x0;\n    cmd->a.y = (short)y0;\n    cmd->b.x = (short)x1;\n    cmd->b.y = (short)y1;\n    cmd->c.x = (short)x2;\n    cmd->c.y = (short)y2;\n    cmd->color = c;\n}\nNK_API void\nnk_stroke_polygon(struct nk_command_buffer *b, const float *points, int point_count,\n    float line_thickness, struct nk_color col)\n{\n    int i;\n    nk_size size = 0;\n    struct nk_command_polygon *cmd;\n\n    NK_ASSERT(b);\n    if (!b || col.a == 0 || line_thickness <= 0) return;\n    size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;\n    cmd = (struct nk_command_polygon*) nk_command_buffer_push(b, NK_COMMAND_POLYGON, size);\n    if (!cmd) return;\n    cmd->color = col;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->point_count = (unsigned short)point_count;\n    for (i = 0; i < point_count; ++i) {\n        cmd->points[i].x = (short)points[i*2];\n        cmd->points[i].y = (short)points[i*2+1];\n    }\n}\nNK_API void\nnk_fill_polygon(struct nk_command_buffer *b, const float *points, int point_count,\n    struct nk_color col)\n{\n    int i;\n    nk_size size = 0;\n    struct nk_command_polygon_filled *cmd;\n\n    NK_ASSERT(b);\n    if (!b || col.a == 0) return;\n    size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;\n    cmd = (struct nk_command_polygon_filled*)\n        nk_command_buffer_push(b, NK_COMMAND_POLYGON_FILLED, size);\n    if (!cmd) return;\n    cmd->color = col;\n    cmd->point_count = (unsigned short)point_count;\n    for (i = 0; i < point_count; ++i) {\n        cmd->points[i].x = (short)points[i*2+0];\n        cmd->points[i].y = (short)points[i*2+1];\n    }\n}\nNK_API void\nnk_stroke_polyline(struct nk_command_buffer *b, const float *points, int point_count,\n    float line_thickness, struct nk_color col)\n{\n    int i;\n    nk_size size = 0;\n    struct nk_command_polyline *cmd;\n\n    NK_ASSERT(b);\n    if (!b || col.a == 0 || line_thickness <= 0) return;\n    size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;\n    cmd = (struct nk_command_polyline*) nk_command_buffer_push(b, NK_COMMAND_POLYLINE, size);\n    if (!cmd) return;\n    cmd->color = col;\n    cmd->point_count = (unsigned short)point_count;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    for (i = 0; i < point_count; ++i) {\n        cmd->points[i].x = (short)points[i*2];\n        cmd->points[i].y = (short)points[i*2+1];\n    }\n}\nNK_API void\nnk_draw_image(struct nk_command_buffer *b, struct nk_rect r,\n    const struct nk_image *img, struct nk_color col)\n{\n    struct nk_command_image *cmd;\n    NK_ASSERT(b);\n    if (!b) return;\n    if (b->use_clipping) {\n        const struct nk_rect *c = &b->clip;\n        if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))\n            return;\n    }\n\n    cmd = (struct nk_command_image*)\n        nk_command_buffer_push(b, NK_COMMAND_IMAGE, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->x = (short)r.x;\n    cmd->y = (short)r.y;\n    cmd->w = (unsigned short)NK_MAX(0, r.w);\n    cmd->h = (unsigned short)NK_MAX(0, r.h);\n    cmd->img = *img;\n    cmd->col = col;\n}\nNK_API void\nnk_draw_nine_slice(struct nk_command_buffer *b, struct nk_rect r,\n    const struct nk_nine_slice *slc, struct nk_color col)\n{\n    struct nk_image img;\n    const struct nk_image *slcimg = (const struct nk_image*)slc;\n    nk_ushort rgnX, rgnY, rgnW, rgnH;\n    rgnX = slcimg->region[0];\n    rgnY = slcimg->region[1];\n    rgnW = slcimg->region[2];\n    rgnH = slcimg->region[3];\n\n    /* top-left */\n    img.handle = slcimg->handle;\n    img.w = slcimg->w;\n    img.h = slcimg->h;\n    img.region[0] = rgnX;\n    img.region[1] = rgnY;\n    img.region[2] = slc->l;\n    img.region[3] = slc->t;\n\n    nk_draw_image(b,\n        nk_rect(r.x, r.y, (float)slc->l, (float)slc->t),\n        &img, col);\n\n#define IMG_RGN(x, y, w, h) img.region[0] = (nk_ushort)(x); img.region[1] = (nk_ushort)(y); img.region[2] = (nk_ushort)(w); img.region[3] = (nk_ushort)(h);\n\n    /* top-center */\n    IMG_RGN(rgnX + slc->l, rgnY, rgnW - slc->l - slc->r, slc->t);\n    nk_draw_image(b,\n        nk_rect(r.x + (float)slc->l, r.y, (float)(r.w - slc->l - slc->r), (float)slc->t),\n        &img, col);\n\n    /* top-right */\n    IMG_RGN(rgnX + rgnW - slc->r, rgnY, slc->r, slc->t);\n    nk_draw_image(b,\n        nk_rect(r.x + r.w - (float)slc->r, r.y, (float)slc->r, (float)slc->t),\n        &img, col);\n\n    /* center-left */\n    IMG_RGN(rgnX, rgnY + slc->t, slc->l, rgnH - slc->t - slc->b);\n    nk_draw_image(b,\n        nk_rect(r.x, r.y + (float)slc->t, (float)slc->l, (float)(r.h - slc->t - slc->b)),\n        &img, col);\n\n    /* center */\n    IMG_RGN(rgnX + slc->l, rgnY + slc->t, rgnW - slc->l - slc->r, rgnH - slc->t - slc->b);\n    nk_draw_image(b,\n        nk_rect(r.x + (float)slc->l, r.y + (float)slc->t, (float)(r.w - slc->l - slc->r), (float)(r.h - slc->t - slc->b)),\n        &img, col);\n\n    /* center-right */\n    IMG_RGN(rgnX + rgnW - slc->r, rgnY + slc->t, slc->r, rgnH - slc->t - slc->b);\n    nk_draw_image(b,\n        nk_rect(r.x + r.w - (float)slc->r, r.y + (float)slc->t, (float)slc->r, (float)(r.h - slc->t - slc->b)),\n        &img, col);\n\n    /* bottom-left */\n    IMG_RGN(rgnX, rgnY + rgnH - slc->b, slc->l, slc->b);\n    nk_draw_image(b,\n        nk_rect(r.x, r.y + r.h - (float)slc->b, (float)slc->l, (float)slc->b),\n        &img, col);\n\n    /* bottom-center */\n    IMG_RGN(rgnX + slc->l, rgnY + rgnH - slc->b, rgnW - slc->l - slc->r, slc->b);\n    nk_draw_image(b,\n        nk_rect(r.x + (float)slc->l, r.y + r.h - (float)slc->b, (float)(r.w - slc->l - slc->r), (float)slc->b),\n        &img, col);\n\n    /* bottom-right */\n    IMG_RGN(rgnX + rgnW - slc->r, rgnY + rgnH - slc->b, slc->r, slc->b);\n    nk_draw_image(b,\n        nk_rect(r.x + r.w - (float)slc->r, r.y + r.h - (float)slc->b, (float)slc->r, (float)slc->b),\n        &img, col);\n\n#undef IMG_RGN\n}\nNK_API void\nnk_push_custom(struct nk_command_buffer *b, struct nk_rect r,\n    nk_command_custom_callback cb, nk_handle usr)\n{\n    struct nk_command_custom *cmd;\n    NK_ASSERT(b);\n    if (!b) return;\n    if (b->use_clipping) {\n        const struct nk_rect *c = &b->clip;\n        if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))\n            return;\n    }\n\n    cmd = (struct nk_command_custom*)\n        nk_command_buffer_push(b, NK_COMMAND_CUSTOM, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->x = (short)r.x;\n    cmd->y = (short)r.y;\n    cmd->w = (unsigned short)NK_MAX(0, r.w);\n    cmd->h = (unsigned short)NK_MAX(0, r.h);\n    cmd->callback_data = usr;\n    cmd->callback = cb;\n}\nNK_API void\nnk_draw_text(struct nk_command_buffer *b, struct nk_rect r,\n    const char *string, int length, const struct nk_user_font *font,\n    struct nk_color bg, struct nk_color fg)\n{\n    float text_width = 0;\n    struct nk_command_text *cmd;\n\n    NK_ASSERT(b);\n    NK_ASSERT(font);\n    if (!b || !string || !length || (bg.a == 0 && fg.a == 0)) return;\n    if (b->use_clipping) {\n        const struct nk_rect *c = &b->clip;\n        if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))\n            return;\n    }\n\n    /* make sure text fits inside bounds */\n    text_width = font->width(font->userdata, font->height, string, length);\n    if (text_width > r.w){\n        int glyphs = 0;\n        float txt_width = (float)text_width;\n        length = nk_text_clamp(font, string, length, r.w, &glyphs, &txt_width, 0,0);\n    }\n\n    if (!length) return;\n    cmd = (struct nk_command_text*)\n        nk_command_buffer_push(b, NK_COMMAND_TEXT, sizeof(*cmd) + (nk_size)(length + 1));\n    if (!cmd) return;\n    cmd->x = (short)r.x;\n    cmd->y = (short)r.y;\n    cmd->w = (unsigned short)r.w;\n    cmd->h = (unsigned short)r.h;\n    cmd->background = bg;\n    cmd->foreground = fg;\n    cmd->font = font;\n    cmd->length = length;\n    cmd->height = font->height;\n    NK_MEMCPY(cmd->string, string, (nk_size)length);\n    cmd->string[length] = '\\0';\n}\n\n\n\n\n/* ===============================================================\n *\n *                              VERTEX\n *\n * ===============================================================*/\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\nNK_API void\nnk_draw_list_init(struct nk_draw_list *list)\n{\n    nk_size i = 0;\n    NK_ASSERT(list);\n    if (!list) return;\n    nk_zero(list, sizeof(*list));\n    for (i = 0; i < NK_LEN(list->circle_vtx); ++i) {\n        const float a = ((float)i / (float)NK_LEN(list->circle_vtx)) * 2 * NK_PI;\n        list->circle_vtx[i].x = (float)NK_COS(a);\n        list->circle_vtx[i].y = (float)NK_SIN(a);\n    }\n}\nNK_API void\nnk_draw_list_setup(struct nk_draw_list *canvas, const struct nk_convert_config *config,\n    struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements,\n    enum nk_anti_aliasing line_aa, enum nk_anti_aliasing shape_aa)\n{\n    NK_ASSERT(canvas);\n    NK_ASSERT(config);\n    NK_ASSERT(cmds);\n    NK_ASSERT(vertices);\n    NK_ASSERT(elements);\n    if (!canvas || !config || !cmds || !vertices || !elements)\n        return;\n\n    canvas->buffer = cmds;\n    canvas->config = *config;\n    canvas->elements = elements;\n    canvas->vertices = vertices;\n    canvas->line_AA = line_aa;\n    canvas->shape_AA = shape_aa;\n    canvas->clip_rect = nk_null_rect;\n\n    canvas->cmd_offset = 0;\n    canvas->element_count = 0;\n    canvas->vertex_count = 0;\n    canvas->cmd_offset = 0;\n    canvas->cmd_count = 0;\n    canvas->path_count = 0;\n}\nNK_API const struct nk_draw_command*\nnk__draw_list_begin(const struct nk_draw_list *canvas, const struct nk_buffer *buffer)\n{\n    nk_byte *memory;\n    nk_size offset;\n    const struct nk_draw_command *cmd;\n\n    NK_ASSERT(buffer);\n    if (!buffer || !buffer->size || !canvas->cmd_count)\n        return 0;\n\n    memory = (nk_byte*)buffer->memory.ptr;\n    offset = buffer->memory.size - canvas->cmd_offset;\n    cmd = nk_ptr_add(const struct nk_draw_command, memory, offset);\n    return cmd;\n}\nNK_API const struct nk_draw_command*\nnk__draw_list_end(const struct nk_draw_list *canvas, const struct nk_buffer *buffer)\n{\n    nk_size size;\n    nk_size offset;\n    nk_byte *memory;\n    const struct nk_draw_command *end;\n\n    NK_ASSERT(buffer);\n    NK_ASSERT(canvas);\n    if (!buffer || !canvas)\n        return 0;\n\n    memory = (nk_byte*)buffer->memory.ptr;\n    size = buffer->memory.size;\n    offset = size - canvas->cmd_offset;\n    end = nk_ptr_add(const struct nk_draw_command, memory, offset);\n    end -= (canvas->cmd_count-1);\n    return end;\n}\nNK_API const struct nk_draw_command*\nnk__draw_list_next(const struct nk_draw_command *cmd,\n    const struct nk_buffer *buffer, const struct nk_draw_list *canvas)\n{\n    const struct nk_draw_command *end;\n    NK_ASSERT(buffer);\n    NK_ASSERT(canvas);\n    if (!cmd || !buffer || !canvas)\n        return 0;\n\n    end = nk__draw_list_end(canvas, buffer);\n    if (cmd <= end) return 0;\n    return (cmd-1);\n}\nNK_INTERN struct nk_vec2*\nnk_draw_list_alloc_path(struct nk_draw_list *list, int count)\n{\n    struct nk_vec2 *points;\n    NK_STORAGE const nk_size point_align = NK_ALIGNOF(struct nk_vec2);\n    NK_STORAGE const nk_size point_size = sizeof(struct nk_vec2);\n    points = (struct nk_vec2*)\n        nk_buffer_alloc(list->buffer, NK_BUFFER_FRONT,\n                        point_size * (nk_size)count, point_align);\n\n    if (!points) return 0;\n    if (!list->path_offset) {\n        void *memory = nk_buffer_memory(list->buffer);\n        list->path_offset = (unsigned int)((nk_byte*)points - (nk_byte*)memory);\n    }\n    list->path_count += (unsigned int)count;\n    return points;\n}\nNK_INTERN struct nk_vec2\nnk_draw_list_path_last(struct nk_draw_list *list)\n{\n    void *memory;\n    struct nk_vec2 *point;\n    NK_ASSERT(list->path_count);\n    memory = nk_buffer_memory(list->buffer);\n    point = nk_ptr_add(struct nk_vec2, memory, list->path_offset);\n    point += (list->path_count-1);\n    return *point;\n}\nNK_INTERN struct nk_draw_command*\nnk_draw_list_push_command(struct nk_draw_list *list, struct nk_rect clip,\n    nk_handle texture)\n{\n    NK_STORAGE const nk_size cmd_align = NK_ALIGNOF(struct nk_draw_command);\n    NK_STORAGE const nk_size cmd_size = sizeof(struct nk_draw_command);\n    struct nk_draw_command *cmd;\n\n    NK_ASSERT(list);\n    cmd = (struct nk_draw_command*)\n        nk_buffer_alloc(list->buffer, NK_BUFFER_BACK, cmd_size, cmd_align);\n\n    if (!cmd) return 0;\n    if (!list->cmd_count) {\n        nk_byte *memory = (nk_byte*)nk_buffer_memory(list->buffer);\n        nk_size total = nk_buffer_total(list->buffer);\n        memory = nk_ptr_add(nk_byte, memory, total);\n        list->cmd_offset = (nk_size)(memory - (nk_byte*)cmd);\n    }\n\n    cmd->elem_count = 0;\n    cmd->clip_rect = clip;\n    cmd->texture = texture;\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    cmd->userdata = list->userdata;\n#endif\n\n    list->cmd_count++;\n    list->clip_rect = clip;\n    return cmd;\n}\nNK_INTERN struct nk_draw_command*\nnk_draw_list_command_last(struct nk_draw_list *list)\n{\n    void *memory;\n    nk_size size;\n    struct nk_draw_command *cmd;\n    NK_ASSERT(list->cmd_count);\n\n    memory = nk_buffer_memory(list->buffer);\n    size = nk_buffer_total(list->buffer);\n    cmd = nk_ptr_add(struct nk_draw_command, memory, size - list->cmd_offset);\n    return (cmd - (list->cmd_count-1));\n}\nNK_INTERN void\nnk_draw_list_add_clip(struct nk_draw_list *list, struct nk_rect rect)\n{\n    NK_ASSERT(list);\n    if (!list) return;\n    if (!list->cmd_count) {\n        nk_draw_list_push_command(list, rect, list->config.tex_null.texture);\n    } else {\n        struct nk_draw_command *prev = nk_draw_list_command_last(list);\n        if (prev->elem_count == 0)\n            prev->clip_rect = rect;\n        nk_draw_list_push_command(list, rect, prev->texture);\n    }\n}\nNK_INTERN void\nnk_draw_list_push_image(struct nk_draw_list *list, nk_handle texture)\n{\n    NK_ASSERT(list);\n    if (!list) return;\n    if (!list->cmd_count) {\n        nk_draw_list_push_command(list, nk_null_rect, texture);\n    } else {\n        struct nk_draw_command *prev = nk_draw_list_command_last(list);\n        if (prev->elem_count == 0) {\n            prev->texture = texture;\n            #ifdef NK_INCLUDE_COMMAND_USERDATA\n            prev->userdata = list->userdata;\n            #endif\n        } else if (prev->texture.id != texture.id\n                #ifdef NK_INCLUDE_COMMAND_USERDATA\n                || prev->userdata.id != list->userdata.id\n                #endif\n                ) {\n            nk_draw_list_push_command(list, prev->clip_rect, texture);\n        }\n    }\n}\n#ifdef NK_INCLUDE_COMMAND_USERDATA\nNK_API void\nnk_draw_list_push_userdata(struct nk_draw_list *list, nk_handle userdata)\n{\n    list->userdata = userdata;\n}\n#endif\nNK_INTERN void*\nnk_draw_list_alloc_vertices(struct nk_draw_list *list, nk_size count)\n{\n    void *vtx;\n    NK_ASSERT(list);\n    if (!list) return 0;\n    vtx = nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT,\n        list->config.vertex_size*count, list->config.vertex_alignment);\n    if (!vtx) return 0;\n    list->vertex_count += (unsigned int)count;\n\n    /* This assert triggers because your are drawing a lot of stuff and nuklear\n     * defined `nk_draw_index` as `nk_ushort` to safe space be default.\n     *\n     * So you reached the maximum number of indices or rather vertexes.\n     * To solve this issue please change typedef `nk_draw_index` to `nk_uint`\n     * and don't forget to specify the new element size in your drawing\n     * backend (OpenGL, DirectX, ...). For example in OpenGL for `glDrawElements`\n     * instead of specifying `GL_UNSIGNED_SHORT` you have to define `GL_UNSIGNED_INT`.\n     * Sorry for the inconvenience. */\n    if(sizeof(nk_draw_index)==2) NK_ASSERT((list->vertex_count < NK_USHORT_MAX &&\n        \"To many vertices for 16-bit vertex indices. Please read comment above on how to solve this problem\"));\n    return vtx;\n}\nNK_INTERN nk_draw_index*\nnk_draw_list_alloc_elements(struct nk_draw_list *list, nk_size count)\n{\n    nk_draw_index *ids;\n    struct nk_draw_command *cmd;\n    NK_STORAGE const nk_size elem_align = NK_ALIGNOF(nk_draw_index);\n    NK_STORAGE const nk_size elem_size = sizeof(nk_draw_index);\n    NK_ASSERT(list);\n    if (!list) return 0;\n\n    ids = (nk_draw_index*)\n        nk_buffer_alloc(list->elements, NK_BUFFER_FRONT, elem_size*count, elem_align);\n    if (!ids) return 0;\n    cmd = nk_draw_list_command_last(list);\n    list->element_count += (unsigned int)count;\n    cmd->elem_count += (unsigned int)count;\n    return ids;\n}\nNK_INTERN int\nnk_draw_vertex_layout_element_is_end_of_layout(\n    const struct nk_draw_vertex_layout_element *element)\n{\n    return (element->attribute == NK_VERTEX_ATTRIBUTE_COUNT ||\n            element->format == NK_FORMAT_COUNT);\n}\nNK_INTERN void\nnk_draw_vertex_color(void *attr, const float *vals,\n    enum nk_draw_vertex_layout_format format)\n{\n    /* if this triggers you tried to provide a value format for a color */\n    float val[4];\n    NK_ASSERT(format >= NK_FORMAT_COLOR_BEGIN);\n    NK_ASSERT(format <= NK_FORMAT_COLOR_END);\n    if (format < NK_FORMAT_COLOR_BEGIN || format > NK_FORMAT_COLOR_END) return;\n\n    val[0] = NK_SATURATE(vals[0]);\n    val[1] = NK_SATURATE(vals[1]);\n    val[2] = NK_SATURATE(vals[2]);\n    val[3] = NK_SATURATE(vals[3]);\n\n    switch (format) {\n    default: NK_ASSERT(0 && \"Invalid vertex layout color format\"); break;\n    case NK_FORMAT_R8G8B8A8:\n    case NK_FORMAT_R8G8B8: {\n        struct nk_color col = nk_rgba_fv(val);\n        NK_MEMCPY(attr, &col.r, sizeof(col));\n    } break;\n    case NK_FORMAT_B8G8R8A8: {\n        struct nk_color col = nk_rgba_fv(val);\n        struct nk_color bgra = nk_rgba(col.b, col.g, col.r, col.a);\n        NK_MEMCPY(attr, &bgra, sizeof(bgra));\n    } break;\n    case NK_FORMAT_R16G15B16: {\n        nk_ushort col[3];\n        col[0] = (nk_ushort)(val[0]*(float)NK_USHORT_MAX);\n        col[1] = (nk_ushort)(val[1]*(float)NK_USHORT_MAX);\n        col[2] = (nk_ushort)(val[2]*(float)NK_USHORT_MAX);\n        NK_MEMCPY(attr, col, sizeof(col));\n    } break;\n    case NK_FORMAT_R16G15B16A16: {\n        nk_ushort col[4];\n        col[0] = (nk_ushort)(val[0]*(float)NK_USHORT_MAX);\n        col[1] = (nk_ushort)(val[1]*(float)NK_USHORT_MAX);\n        col[2] = (nk_ushort)(val[2]*(float)NK_USHORT_MAX);\n        col[3] = (nk_ushort)(val[3]*(float)NK_USHORT_MAX);\n        NK_MEMCPY(attr, col, sizeof(col));\n    } break;\n    case NK_FORMAT_R32G32B32: {\n        nk_uint col[3];\n        col[0] = (nk_uint)(val[0]*(float)NK_UINT_MAX);\n        col[1] = (nk_uint)(val[1]*(float)NK_UINT_MAX);\n        col[2] = (nk_uint)(val[2]*(float)NK_UINT_MAX);\n        NK_MEMCPY(attr, col, sizeof(col));\n    } break;\n    case NK_FORMAT_R32G32B32A32: {\n        nk_uint col[4];\n        col[0] = (nk_uint)(val[0]*(float)NK_UINT_MAX);\n        col[1] = (nk_uint)(val[1]*(float)NK_UINT_MAX);\n        col[2] = (nk_uint)(val[2]*(float)NK_UINT_MAX);\n        col[3] = (nk_uint)(val[3]*(float)NK_UINT_MAX);\n        NK_MEMCPY(attr, col, sizeof(col));\n    } break;\n    case NK_FORMAT_R32G32B32A32_FLOAT:\n        NK_MEMCPY(attr, val, sizeof(float)*4);\n        break;\n    case NK_FORMAT_R32G32B32A32_DOUBLE: {\n        double col[4];\n        col[0] = (double)val[0];\n        col[1] = (double)val[1];\n        col[2] = (double)val[2];\n        col[3] = (double)val[3];\n        NK_MEMCPY(attr, col, sizeof(col));\n    } break;\n    case NK_FORMAT_RGB32:\n    case NK_FORMAT_RGBA32: {\n        struct nk_color col = nk_rgba_fv(val);\n        nk_uint color = nk_color_u32(col);\n        NK_MEMCPY(attr, &color, sizeof(color));\n    } break; }\n}\nNK_INTERN void\nnk_draw_vertex_element(void *dst, const float *values, int value_count,\n    enum nk_draw_vertex_layout_format format)\n{\n    int value_index;\n    void *attribute = dst;\n    /* if this triggers you tried to provide a color format for a value */\n    NK_ASSERT(format < NK_FORMAT_COLOR_BEGIN);\n    if (format >= NK_FORMAT_COLOR_BEGIN && format <= NK_FORMAT_COLOR_END) return;\n    for (value_index = 0; value_index < value_count; ++value_index) {\n        switch (format) {\n        default: NK_ASSERT(0 && \"invalid vertex layout format\"); break;\n        case NK_FORMAT_SCHAR: {\n            char value = (char)NK_CLAMP((float)NK_SCHAR_MIN, values[value_index], (float)NK_SCHAR_MAX);\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(char));\n        } break;\n        case NK_FORMAT_SSHORT: {\n            nk_short value = (nk_short)NK_CLAMP((float)NK_SSHORT_MIN, values[value_index], (float)NK_SSHORT_MAX);\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(value));\n        } break;\n        case NK_FORMAT_SINT: {\n            nk_int value = (nk_int)NK_CLAMP((float)NK_SINT_MIN, values[value_index], (float)NK_SINT_MAX);\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(nk_int));\n        } break;\n        case NK_FORMAT_UCHAR: {\n            unsigned char value = (unsigned char)NK_CLAMP((float)NK_UCHAR_MIN, values[value_index], (float)NK_UCHAR_MAX);\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(unsigned char));\n        } break;\n        case NK_FORMAT_USHORT: {\n            nk_ushort value = (nk_ushort)NK_CLAMP((float)NK_USHORT_MIN, values[value_index], (float)NK_USHORT_MAX);\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(value));\n            } break;\n        case NK_FORMAT_UINT: {\n            nk_uint value = (nk_uint)NK_CLAMP((float)NK_UINT_MIN, values[value_index], (float)NK_UINT_MAX);\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(nk_uint));\n        } break;\n        case NK_FORMAT_FLOAT:\n            NK_MEMCPY(attribute, &values[value_index], sizeof(values[value_index]));\n            attribute = (void*)((char*)attribute + sizeof(float));\n            break;\n        case NK_FORMAT_DOUBLE: {\n            double value = (double)values[value_index];\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(double));\n            } break;\n        }\n    }\n}\nNK_INTERN void*\nnk_draw_vertex(void *dst, const struct nk_convert_config *config,\n    struct nk_vec2 pos, struct nk_vec2 uv, struct nk_colorf color)\n{\n    void *result = (void*)((char*)dst + config->vertex_size);\n    const struct nk_draw_vertex_layout_element *elem_iter = config->vertex_layout;\n    while (!nk_draw_vertex_layout_element_is_end_of_layout(elem_iter)) {\n        void *address = (void*)((char*)dst + elem_iter->offset);\n        switch (elem_iter->attribute) {\n        case NK_VERTEX_ATTRIBUTE_COUNT:\n        default: NK_ASSERT(0 && \"wrong element attribute\"); break;\n        case NK_VERTEX_POSITION: nk_draw_vertex_element(address, &pos.x, 2, elem_iter->format); break;\n        case NK_VERTEX_TEXCOORD: nk_draw_vertex_element(address, &uv.x, 2, elem_iter->format); break;\n        case NK_VERTEX_COLOR: nk_draw_vertex_color(address, &color.r, elem_iter->format); break;\n        }\n        elem_iter++;\n    }\n    return result;\n}\nNK_API void\nnk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *points,\n    const unsigned int points_count, struct nk_color color, enum nk_draw_list_stroke closed,\n    float thickness, enum nk_anti_aliasing aliasing)\n{\n    nk_size count;\n    int thick_line;\n    struct nk_colorf col;\n    struct nk_colorf col_trans;\n    NK_ASSERT(list);\n    if (!list || points_count < 2) return;\n\n    color.a = (nk_byte)((float)color.a * list->config.global_alpha);\n    count = points_count;\n    if (!closed) count = points_count-1;\n    thick_line = thickness > 1.0f;\n\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    nk_draw_list_push_userdata(list, list->userdata);\n#endif\n\n    color.a = (nk_byte)((float)color.a * list->config.global_alpha);\n    nk_color_fv(&col.r, color);\n    col_trans = col;\n    col_trans.a = 0;\n\n    if (aliasing == NK_ANTI_ALIASING_ON) {\n        /* ANTI-ALIASED STROKE */\n        const float AA_SIZE = 1.0f;\n        NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2);\n        NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2);\n\n        /* allocate vertices and elements  */\n        nk_size i1 = 0;\n        nk_size vertex_offset;\n        nk_size index = list->vertex_count;\n\n        const nk_size idx_count = (thick_line) ?  (count * 18) : (count * 12);\n        const nk_size vtx_count = (thick_line) ? (points_count * 4): (points_count *3);\n\n        void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);\n        nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);\n\n        nk_size size;\n        struct nk_vec2 *normals, *temp;\n        if (!vtx || !ids) return;\n\n        /* temporary allocate normals + points */\n        vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr);\n        nk_buffer_mark(list->vertices, NK_BUFFER_FRONT);\n        size = pnt_size * ((thick_line) ? 5 : 3) * points_count;\n        normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align);\n        if (!normals) return;\n        temp = normals + points_count;\n\n        /* make sure vertex pointer is still correct */\n        vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset);\n\n        /* calculate normals */\n        for (i1 = 0; i1 < count; ++i1) {\n            const nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1);\n            struct nk_vec2 diff = nk_vec2_sub(points[i2], points[i1]);\n            float len;\n\n            /* vec2 inverted length  */\n            len = nk_vec2_len_sqr(diff);\n            if (len != 0.0f)\n                len = NK_INV_SQRT(len);\n            else len = 1.0f;\n\n            diff = nk_vec2_muls(diff, len);\n            normals[i1].x = diff.y;\n            normals[i1].y = -diff.x;\n        }\n\n        if (!closed)\n            normals[points_count-1] = normals[points_count-2];\n\n        if (!thick_line) {\n            nk_size idx1, i;\n            if (!closed) {\n                struct nk_vec2 d;\n                temp[0] = nk_vec2_add(points[0], nk_vec2_muls(normals[0], AA_SIZE));\n                temp[1] = nk_vec2_sub(points[0], nk_vec2_muls(normals[0], AA_SIZE));\n                d = nk_vec2_muls(normals[points_count-1], AA_SIZE);\n                temp[(points_count-1) * 2 + 0] = nk_vec2_add(points[points_count-1], d);\n                temp[(points_count-1) * 2 + 1] = nk_vec2_sub(points[points_count-1], d);\n            }\n\n            /* fill elements */\n            idx1 = index;\n            for (i1 = 0; i1 < count; i1++) {\n                struct nk_vec2 dm;\n                float dmr2;\n                nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1);\n                nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 3);\n\n                /* average normals */\n                dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f);\n                dmr2 = dm.x * dm.x + dm.y* dm.y;\n                if (dmr2 > 0.000001f) {\n                    float scale = 1.0f/dmr2;\n                    scale = NK_MIN(100.0f, scale);\n                    dm = nk_vec2_muls(dm, scale);\n                }\n\n                dm = nk_vec2_muls(dm, AA_SIZE);\n                temp[i2*2+0] = nk_vec2_add(points[i2], dm);\n                temp[i2*2+1] = nk_vec2_sub(points[i2], dm);\n\n                ids[0] = (nk_draw_index)(idx2 + 0); ids[1] = (nk_draw_index)(idx1+0);\n                ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2);\n                ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+0);\n                ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1);\n                ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0);\n                ids[10]= (nk_draw_index)(idx2 + 0); ids[11]= (nk_draw_index)(idx2+1);\n                ids += 12;\n                idx1 = idx2;\n            }\n\n            /* fill vertices */\n            for (i = 0; i < points_count; ++i) {\n                const struct nk_vec2 uv = list->config.tex_null.uv;\n                vtx = nk_draw_vertex(vtx, &list->config, points[i], uv, col);\n                vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+0], uv, col_trans);\n                vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+1], uv, col_trans);\n            }\n        } else {\n            nk_size idx1, i;\n            const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;\n            if (!closed) {\n                struct nk_vec2 d1 = nk_vec2_muls(normals[0], half_inner_thickness + AA_SIZE);\n                struct nk_vec2 d2 = nk_vec2_muls(normals[0], half_inner_thickness);\n\n                temp[0] = nk_vec2_add(points[0], d1);\n                temp[1] = nk_vec2_add(points[0], d2);\n                temp[2] = nk_vec2_sub(points[0], d2);\n                temp[3] = nk_vec2_sub(points[0], d1);\n\n                d1 = nk_vec2_muls(normals[points_count-1], half_inner_thickness + AA_SIZE);\n                d2 = nk_vec2_muls(normals[points_count-1], half_inner_thickness);\n\n                temp[(points_count-1)*4+0] = nk_vec2_add(points[points_count-1], d1);\n                temp[(points_count-1)*4+1] = nk_vec2_add(points[points_count-1], d2);\n                temp[(points_count-1)*4+2] = nk_vec2_sub(points[points_count-1], d2);\n                temp[(points_count-1)*4+3] = nk_vec2_sub(points[points_count-1], d1);\n            }\n\n            /* add all elements */\n            idx1 = index;\n            for (i1 = 0; i1 < count; ++i1) {\n                struct nk_vec2 dm_out, dm_in;\n                const nk_size i2 = ((i1+1) == points_count) ? 0: (i1 + 1);\n                nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 4);\n\n                /* average normals */\n                struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f);\n                float dmr2 = dm.x * dm.x + dm.y* dm.y;\n                if (dmr2 > 0.000001f) {\n                    float scale = 1.0f/dmr2;\n                    scale = NK_MIN(100.0f, scale);\n                    dm = nk_vec2_muls(dm, scale);\n                }\n\n                dm_out = nk_vec2_muls(dm, ((half_inner_thickness) + AA_SIZE));\n                dm_in = nk_vec2_muls(dm, half_inner_thickness);\n                temp[i2*4+0] = nk_vec2_add(points[i2], dm_out);\n                temp[i2*4+1] = nk_vec2_add(points[i2], dm_in);\n                temp[i2*4+2] = nk_vec2_sub(points[i2], dm_in);\n                temp[i2*4+3] = nk_vec2_sub(points[i2], dm_out);\n\n                /* add indexes */\n                ids[0] = (nk_draw_index)(idx2 + 1); ids[1] = (nk_draw_index)(idx1+1);\n                ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2);\n                ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+1);\n                ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1);\n                ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0);\n                ids[10]= (nk_draw_index)(idx2 + 0); ids[11] = (nk_draw_index)(idx2+1);\n                ids[12]= (nk_draw_index)(idx2 + 2); ids[13] = (nk_draw_index)(idx1+2);\n                ids[14]= (nk_draw_index)(idx1 + 3); ids[15] = (nk_draw_index)(idx1+3);\n                ids[16]= (nk_draw_index)(idx2 + 3); ids[17] = (nk_draw_index)(idx2+2);\n                ids += 18;\n                idx1 = idx2;\n            }\n\n            /* add vertices */\n            for (i = 0; i < points_count; ++i) {\n                const struct nk_vec2 uv = list->config.tex_null.uv;\n                vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+0], uv, col_trans);\n                vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+1], uv, col);\n                vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+2], uv, col);\n                vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+3], uv, col_trans);\n            }\n        }\n        /* free temporary normals + points */\n        nk_buffer_reset(list->vertices, NK_BUFFER_FRONT);\n    } else {\n        /* NON ANTI-ALIASED STROKE */\n        nk_size i1 = 0;\n        nk_size idx = list->vertex_count;\n        const nk_size idx_count = count * 6;\n        const nk_size vtx_count = count * 4;\n        void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);\n        nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);\n        if (!vtx || !ids) return;\n\n        for (i1 = 0; i1 < count; ++i1) {\n            float dx, dy;\n            const struct nk_vec2 uv = list->config.tex_null.uv;\n            const nk_size i2 = ((i1+1) == points_count) ? 0 : i1 + 1;\n            const struct nk_vec2 p1 = points[i1];\n            const struct nk_vec2 p2 = points[i2];\n            struct nk_vec2 diff = nk_vec2_sub(p2, p1);\n            float len;\n\n            /* vec2 inverted length  */\n            len = nk_vec2_len_sqr(diff);\n            if (len != 0.0f)\n                len = NK_INV_SQRT(len);\n            else len = 1.0f;\n            diff = nk_vec2_muls(diff, len);\n\n            /* add vertices */\n            dx = diff.x * (thickness * 0.5f);\n            dy = diff.y * (thickness * 0.5f);\n\n            vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x + dy, p1.y - dx), uv, col);\n            vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x + dy, p2.y - dx), uv, col);\n            vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x - dy, p2.y + dx), uv, col);\n            vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x - dy, p1.y + dx), uv, col);\n\n            ids[0] = (nk_draw_index)(idx+0); ids[1] = (nk_draw_index)(idx+1);\n            ids[2] = (nk_draw_index)(idx+2); ids[3] = (nk_draw_index)(idx+0);\n            ids[4] = (nk_draw_index)(idx+2); ids[5] = (nk_draw_index)(idx+3);\n\n            ids += 6;\n            idx += 4;\n        }\n    }\n}\nNK_API void\nnk_draw_list_fill_poly_convex(struct nk_draw_list *list,\n    const struct nk_vec2 *points, const unsigned int points_count,\n    struct nk_color color, enum nk_anti_aliasing aliasing)\n{\n    struct nk_colorf col;\n    struct nk_colorf col_trans;\n\n    NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2);\n    NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2);\n    NK_ASSERT(list);\n    if (!list || points_count < 3) return;\n\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    nk_draw_list_push_userdata(list, list->userdata);\n#endif\n\n    color.a = (nk_byte)((float)color.a * list->config.global_alpha);\n    nk_color_fv(&col.r, color);\n    col_trans = col;\n    col_trans.a = 0;\n\n    if (aliasing == NK_ANTI_ALIASING_ON) {\n        nk_size i = 0;\n        nk_size i0 = 0;\n        nk_size i1 = 0;\n\n        const float AA_SIZE = 1.0f;\n        nk_size vertex_offset = 0;\n        nk_size index = list->vertex_count;\n\n        const nk_size idx_count = (points_count-2)*3 + points_count*6;\n        const nk_size vtx_count = (points_count*2);\n\n        void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);\n        nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);\n\n        nk_size size = 0;\n        struct nk_vec2 *normals = 0;\n        unsigned int vtx_inner_idx = (unsigned int)(index + 0);\n        unsigned int vtx_outer_idx = (unsigned int)(index + 1);\n        if (!vtx || !ids) return;\n\n        /* temporary allocate normals */\n        vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr);\n        nk_buffer_mark(list->vertices, NK_BUFFER_FRONT);\n        size = pnt_size * points_count;\n        normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align);\n        if (!normals) return;\n        vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset);\n\n        /* add elements */\n        for (i = 2; i < points_count; i++) {\n            ids[0] = (nk_draw_index)(vtx_inner_idx);\n            ids[1] = (nk_draw_index)(vtx_inner_idx + ((i-1) << 1));\n            ids[2] = (nk_draw_index)(vtx_inner_idx + (i << 1));\n            ids += 3;\n        }\n\n        /* compute normals */\n        for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) {\n            struct nk_vec2 p0 = points[i0];\n            struct nk_vec2 p1 = points[i1];\n            struct nk_vec2 diff = nk_vec2_sub(p1, p0);\n\n            /* vec2 inverted length  */\n            float len = nk_vec2_len_sqr(diff);\n            if (len != 0.0f)\n                len = NK_INV_SQRT(len);\n            else len = 1.0f;\n            diff = nk_vec2_muls(diff, len);\n\n            normals[i0].x = diff.y;\n            normals[i0].y = -diff.x;\n        }\n\n        /* add vertices + indexes */\n        for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) {\n            const struct nk_vec2 uv = list->config.tex_null.uv;\n            struct nk_vec2 n0 = normals[i0];\n            struct nk_vec2 n1 = normals[i1];\n            struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(n0, n1), 0.5f);\n            float dmr2 = dm.x*dm.x + dm.y*dm.y;\n            if (dmr2 > 0.000001f) {\n                float scale = 1.0f / dmr2;\n                scale = NK_MIN(scale, 100.0f);\n                dm = nk_vec2_muls(dm, scale);\n            }\n            dm = nk_vec2_muls(dm, AA_SIZE * 0.5f);\n\n            /* add vertices */\n            vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_sub(points[i1], dm), uv, col);\n            vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_add(points[i1], dm), uv, col_trans);\n\n            /* add indexes */\n            ids[0] = (nk_draw_index)(vtx_inner_idx+(i1<<1));\n            ids[1] = (nk_draw_index)(vtx_inner_idx+(i0<<1));\n            ids[2] = (nk_draw_index)(vtx_outer_idx+(i0<<1));\n            ids[3] = (nk_draw_index)(vtx_outer_idx+(i0<<1));\n            ids[4] = (nk_draw_index)(vtx_outer_idx+(i1<<1));\n            ids[5] = (nk_draw_index)(vtx_inner_idx+(i1<<1));\n            ids += 6;\n        }\n        /* free temporary normals + points */\n        nk_buffer_reset(list->vertices, NK_BUFFER_FRONT);\n    } else {\n        nk_size i = 0;\n        nk_size index = list->vertex_count;\n        const nk_size idx_count = (points_count-2)*3;\n        const nk_size vtx_count = points_count;\n        void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);\n        nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);\n\n        if (!vtx || !ids) return;\n        for (i = 0; i < vtx_count; ++i)\n            vtx = nk_draw_vertex(vtx, &list->config, points[i], list->config.tex_null.uv, col);\n        for (i = 2; i < points_count; ++i) {\n            ids[0] = (nk_draw_index)index;\n            ids[1] = (nk_draw_index)(index+ i - 1);\n            ids[2] = (nk_draw_index)(index+i);\n            ids += 3;\n        }\n    }\n}\nNK_API void\nnk_draw_list_path_clear(struct nk_draw_list *list)\n{\n    NK_ASSERT(list);\n    if (!list) return;\n    nk_buffer_reset(list->buffer, NK_BUFFER_FRONT);\n    list->path_count = 0;\n    list->path_offset = 0;\n}\nNK_API void\nnk_draw_list_path_line_to(struct nk_draw_list *list, struct nk_vec2 pos)\n{\n    struct nk_vec2 *points = 0;\n    struct nk_draw_command *cmd = 0;\n    NK_ASSERT(list);\n    if (!list) return;\n    if (!list->cmd_count)\n        nk_draw_list_add_clip(list, nk_null_rect);\n\n    cmd = nk_draw_list_command_last(list);\n    if (cmd && cmd->texture.ptr != list->config.tex_null.texture.ptr)\n        nk_draw_list_push_image(list, list->config.tex_null.texture);\n\n    points = nk_draw_list_alloc_path(list, 1);\n    if (!points) return;\n    points[0] = pos;\n}\nNK_API void\nnk_draw_list_path_arc_to_fast(struct nk_draw_list *list, struct nk_vec2 center,\n    float radius, int a_min, int a_max)\n{\n    int a = 0;\n    NK_ASSERT(list);\n    if (!list) return;\n    if (a_min <= a_max) {\n        for (a = a_min; a <= a_max; a++) {\n            const struct nk_vec2 c = list->circle_vtx[(nk_size)a % NK_LEN(list->circle_vtx)];\n            const float x = center.x + c.x * radius;\n            const float y = center.y + c.y * radius;\n            nk_draw_list_path_line_to(list, nk_vec2(x, y));\n        }\n    }\n}\nNK_API void\nnk_draw_list_path_arc_to(struct nk_draw_list *list, struct nk_vec2 center,\n    float radius, float a_min, float a_max, unsigned int segments)\n{\n    unsigned int i = 0;\n    NK_ASSERT(list);\n    if (!list) return;\n    if (radius == 0.0f) return;\n\n    /*  This algorithm for arc drawing relies on these two trigonometric identities[1]:\n            sin(a + b) = sin(a) * cos(b) + cos(a) * sin(b)\n            cos(a + b) = cos(a) * cos(b) - sin(a) * sin(b)\n\n        Two coordinates (x, y) of a point on a circle centered on\n        the origin can be written in polar form as:\n            x = r * cos(a)\n            y = r * sin(a)\n        where r is the radius of the circle,\n            a is the angle between (x, y) and the origin.\n\n        This allows us to rotate the coordinates around the\n        origin by an angle b using the following transformation:\n            x' = r * cos(a + b) = x * cos(b) - y * sin(b)\n            y' = r * sin(a + b) = y * cos(b) + x * sin(b)\n\n        [1] https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Angle_sum_and_difference_identities\n    */\n    {const float d_angle = (a_max - a_min) / (float)segments;\n    const float sin_d = (float)NK_SIN(d_angle);\n    const float cos_d = (float)NK_COS(d_angle);\n\n    float cx = (float)NK_COS(a_min) * radius;\n    float cy = (float)NK_SIN(a_min) * radius;\n    for(i = 0; i <= segments; ++i) {\n        float new_cx, new_cy;\n        const float x = center.x + cx;\n        const float y = center.y + cy;\n        nk_draw_list_path_line_to(list, nk_vec2(x, y));\n\n        new_cx = cx * cos_d - cy * sin_d;\n        new_cy = cy * cos_d + cx * sin_d;\n        cx = new_cx;\n        cy = new_cy;\n    }}\n}\nNK_API void\nnk_draw_list_path_rect_to(struct nk_draw_list *list, struct nk_vec2 a,\n    struct nk_vec2 b, float rounding)\n{\n    float r;\n    NK_ASSERT(list);\n    if (!list) return;\n    r = rounding;\n    r = NK_MIN(r, ((b.x-a.x) < 0) ? -(b.x-a.x): (b.x-a.x));\n    r = NK_MIN(r, ((b.y-a.y) < 0) ? -(b.y-a.y): (b.y-a.y));\n\n    if (r == 0.0f) {\n        nk_draw_list_path_line_to(list, a);\n        nk_draw_list_path_line_to(list, nk_vec2(b.x,a.y));\n        nk_draw_list_path_line_to(list, b);\n        nk_draw_list_path_line_to(list, nk_vec2(a.x,b.y));\n    } else {\n        nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, a.y + r), r, 6, 9);\n        nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, a.y + r), r, 9, 12);\n        nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, b.y - r), r, 0, 3);\n        nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, b.y - r), r, 3, 6);\n    }\n}\nNK_API void\nnk_draw_list_path_curve_to(struct nk_draw_list *list, struct nk_vec2 p2,\n    struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments)\n{\n    float t_step;\n    unsigned int i_step;\n    struct nk_vec2 p1;\n\n    NK_ASSERT(list);\n    NK_ASSERT(list->path_count);\n    if (!list || !list->path_count) return;\n    num_segments = NK_MAX(num_segments, 1);\n\n    p1 = nk_draw_list_path_last(list);\n    t_step = 1.0f/(float)num_segments;\n    for (i_step = 1; i_step <= num_segments; ++i_step) {\n        float t = t_step * (float)i_step;\n        float u = 1.0f - t;\n        float w1 = u*u*u;\n        float w2 = 3*u*u*t;\n        float w3 = 3*u*t*t;\n        float w4 = t * t *t;\n        float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x;\n        float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y;\n        nk_draw_list_path_line_to(list, nk_vec2(x,y));\n    }\n}\nNK_API void\nnk_draw_list_path_fill(struct nk_draw_list *list, struct nk_color color)\n{\n    struct nk_vec2 *points;\n    NK_ASSERT(list);\n    if (!list) return;\n    points = (struct nk_vec2*)nk_buffer_memory(list->buffer);\n    nk_draw_list_fill_poly_convex(list, points, list->path_count, color, list->config.shape_AA);\n    nk_draw_list_path_clear(list);\n}\nNK_API void\nnk_draw_list_path_stroke(struct nk_draw_list *list, struct nk_color color,\n    enum nk_draw_list_stroke closed, float thickness)\n{\n    struct nk_vec2 *points;\n    NK_ASSERT(list);\n    if (!list) return;\n    points = (struct nk_vec2*)nk_buffer_memory(list->buffer);\n    nk_draw_list_stroke_poly_line(list, points, list->path_count, color,\n        closed, thickness, list->config.line_AA);\n    nk_draw_list_path_clear(list);\n}\nNK_API void\nnk_draw_list_stroke_line(struct nk_draw_list *list, struct nk_vec2 a,\n    struct nk_vec2 b, struct nk_color col, float thickness)\n{\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    if (list->line_AA == NK_ANTI_ALIASING_ON) {\n        nk_draw_list_path_line_to(list, a);\n        nk_draw_list_path_line_to(list, b);\n    } else {\n        nk_draw_list_path_line_to(list, nk_vec2_sub(a,nk_vec2(0.5f,0.5f)));\n        nk_draw_list_path_line_to(list, nk_vec2_sub(b,nk_vec2(0.5f,0.5f)));\n    }\n    nk_draw_list_path_stroke(list,  col, NK_STROKE_OPEN, thickness);\n}\nNK_API void\nnk_draw_list_fill_rect(struct nk_draw_list *list, struct nk_rect rect,\n    struct nk_color col, float rounding)\n{\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n\n    if (list->line_AA == NK_ANTI_ALIASING_ON) {\n        nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y),\n            nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);\n    } else {\n        nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f),\n            nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);\n    } nk_draw_list_path_fill(list,  col);\n}\nNK_API void\nnk_draw_list_stroke_rect(struct nk_draw_list *list, struct nk_rect rect,\n    struct nk_color col, float rounding, float thickness)\n{\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    if (list->line_AA == NK_ANTI_ALIASING_ON) {\n        nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y),\n            nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);\n    } else {\n        nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f),\n            nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);\n    } nk_draw_list_path_stroke(list,  col, NK_STROKE_CLOSED, thickness);\n}\nNK_API void\nnk_draw_list_fill_rect_multi_color(struct nk_draw_list *list, struct nk_rect rect,\n    struct nk_color left, struct nk_color top, struct nk_color right,\n    struct nk_color bottom)\n{\n    void *vtx;\n    struct nk_colorf col_left, col_top;\n    struct nk_colorf col_right, col_bottom;\n    nk_draw_index *idx;\n    nk_draw_index index;\n\n    nk_color_fv(&col_left.r, left);\n    nk_color_fv(&col_right.r, right);\n    nk_color_fv(&col_top.r, top);\n    nk_color_fv(&col_bottom.r, bottom);\n\n    NK_ASSERT(list);\n    if (!list) return;\n\n    nk_draw_list_push_image(list, list->config.tex_null.texture);\n    index = (nk_draw_index)list->vertex_count;\n    vtx = nk_draw_list_alloc_vertices(list, 4);\n    idx = nk_draw_list_alloc_elements(list, 6);\n    if (!vtx || !idx) return;\n\n    idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1);\n    idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0);\n    idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3);\n\n    vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y), list->config.tex_null.uv, col_left);\n    vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y), list->config.tex_null.uv, col_top);\n    vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y + rect.h), list->config.tex_null.uv, col_right);\n    vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y + rect.h), list->config.tex_null.uv, col_bottom);\n}\nNK_API void\nnk_draw_list_fill_triangle(struct nk_draw_list *list, struct nk_vec2 a,\n    struct nk_vec2 b, struct nk_vec2 c, struct nk_color col)\n{\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    nk_draw_list_path_line_to(list, a);\n    nk_draw_list_path_line_to(list, b);\n    nk_draw_list_path_line_to(list, c);\n    nk_draw_list_path_fill(list, col);\n}\nNK_API void\nnk_draw_list_stroke_triangle(struct nk_draw_list *list, struct nk_vec2 a,\n    struct nk_vec2 b, struct nk_vec2 c, struct nk_color col, float thickness)\n{\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    nk_draw_list_path_line_to(list, a);\n    nk_draw_list_path_line_to(list, b);\n    nk_draw_list_path_line_to(list, c);\n    nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);\n}\nNK_API void\nnk_draw_list_fill_circle(struct nk_draw_list *list, struct nk_vec2 center,\n    float radius, struct nk_color col, unsigned int segs)\n{\n    float a_max;\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs;\n    nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs);\n    nk_draw_list_path_fill(list, col);\n}\nNK_API void\nnk_draw_list_stroke_circle(struct nk_draw_list *list, struct nk_vec2 center,\n    float radius, struct nk_color col, unsigned int segs, float thickness)\n{\n    float a_max;\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs;\n    nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs);\n    nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);\n}\nNK_API void\nnk_draw_list_stroke_curve(struct nk_draw_list *list, struct nk_vec2 p0,\n    struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1,\n    struct nk_color col, unsigned int segments, float thickness)\n{\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    nk_draw_list_path_line_to(list, p0);\n    nk_draw_list_path_curve_to(list, cp0, cp1, p1, segments);\n    nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness);\n}\nNK_INTERN void\nnk_draw_list_push_rect_uv(struct nk_draw_list *list, struct nk_vec2 a,\n    struct nk_vec2 c, struct nk_vec2 uva, struct nk_vec2 uvc,\n    struct nk_color color)\n{\n    void *vtx;\n    struct nk_vec2 uvb;\n    struct nk_vec2 uvd;\n    struct nk_vec2 b;\n    struct nk_vec2 d;\n\n    struct nk_colorf col;\n    nk_draw_index *idx;\n    nk_draw_index index;\n    NK_ASSERT(list);\n    if (!list) return;\n\n    nk_color_fv(&col.r, color);\n    uvb = nk_vec2(uvc.x, uva.y);\n    uvd = nk_vec2(uva.x, uvc.y);\n    b = nk_vec2(c.x, a.y);\n    d = nk_vec2(a.x, c.y);\n\n    index = (nk_draw_index)list->vertex_count;\n    vtx = nk_draw_list_alloc_vertices(list, 4);\n    idx = nk_draw_list_alloc_elements(list, 6);\n    if (!vtx || !idx) return;\n\n    idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1);\n    idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0);\n    idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3);\n\n    vtx = nk_draw_vertex(vtx, &list->config, a, uva, col);\n    vtx = nk_draw_vertex(vtx, &list->config, b, uvb, col);\n    vtx = nk_draw_vertex(vtx, &list->config, c, uvc, col);\n    vtx = nk_draw_vertex(vtx, &list->config, d, uvd, col);\n}\nNK_API void\nnk_draw_list_add_image(struct nk_draw_list *list, struct nk_image texture,\n    struct nk_rect rect, struct nk_color color)\n{\n    NK_ASSERT(list);\n    if (!list) return;\n    /* push new command with given texture */\n    nk_draw_list_push_image(list, texture.handle);\n    if (nk_image_is_subimage(&texture)) {\n        /* add region inside of the texture  */\n        struct nk_vec2 uv[2];\n        uv[0].x = (float)texture.region[0]/(float)texture.w;\n        uv[0].y = (float)texture.region[1]/(float)texture.h;\n        uv[1].x = (float)(texture.region[0] + texture.region[2])/(float)texture.w;\n        uv[1].y = (float)(texture.region[1] + texture.region[3])/(float)texture.h;\n        nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y),\n            nk_vec2(rect.x + rect.w, rect.y + rect.h),  uv[0], uv[1], color);\n    } else nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y),\n            nk_vec2(rect.x + rect.w, rect.y + rect.h),\n            nk_vec2(0.0f, 0.0f), nk_vec2(1.0f, 1.0f),color);\n}\nNK_API void\nnk_draw_list_add_text(struct nk_draw_list *list, const struct nk_user_font *font,\n    struct nk_rect rect, const char *text, int len, float font_height,\n    struct nk_color fg)\n{\n    float x = 0;\n    int text_len = 0;\n    nk_rune unicode = 0;\n    nk_rune next = 0;\n    int glyph_len = 0;\n    int next_glyph_len = 0;\n    struct nk_user_font_glyph g;\n\n    NK_ASSERT(list);\n    if (!list || !len || !text) return;\n    if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,\n        list->clip_rect.x, list->clip_rect.y, list->clip_rect.w, list->clip_rect.h)) return;\n\n    nk_draw_list_push_image(list, font->texture);\n    x = rect.x;\n    glyph_len = nk_utf_decode(text, &unicode, len);\n    if (!glyph_len) return;\n\n    /* draw every glyph image */\n    fg.a = (nk_byte)((float)fg.a * list->config.global_alpha);\n    while (text_len < len && glyph_len) {\n        float gx, gy, gh, gw;\n        float char_width = 0;\n        if (unicode == NK_UTF_INVALID) break;\n\n        /* query currently drawn glyph information */\n        next_glyph_len = nk_utf_decode(text + text_len + glyph_len, &next, (int)len - text_len);\n        font->query(font->userdata, font_height, &g, unicode,\n                    (next == NK_UTF_INVALID) ? '\\0' : next);\n\n        /* calculate and draw glyph drawing rectangle and image */\n        gx = x + g.offset.x;\n        gy = rect.y + g.offset.y;\n        gw = g.width; gh = g.height;\n        char_width = g.xadvance;\n        nk_draw_list_push_rect_uv(list, nk_vec2(gx,gy), nk_vec2(gx + gw, gy+ gh),\n            g.uv[0], g.uv[1], fg);\n\n        /* offset next glyph */\n        text_len += glyph_len;\n        x += char_width;\n        glyph_len = next_glyph_len;\n        unicode = next;\n    }\n}\nNK_API nk_flags\nnk_convert(struct nk_context *ctx, struct nk_buffer *cmds,\n    struct nk_buffer *vertices, struct nk_buffer *elements,\n    const struct nk_convert_config *config)\n{\n    nk_flags res = NK_CONVERT_SUCCESS;\n    const struct nk_command *cmd;\n    NK_ASSERT(ctx);\n    NK_ASSERT(cmds);\n    NK_ASSERT(vertices);\n    NK_ASSERT(elements);\n    NK_ASSERT(config);\n    NK_ASSERT(config->vertex_layout);\n    NK_ASSERT(config->vertex_size);\n    if (!ctx || !cmds || !vertices || !elements || !config || !config->vertex_layout)\n        return NK_CONVERT_INVALID_PARAM;\n\n    nk_draw_list_setup(&ctx->draw_list, config, cmds, vertices, elements,\n        config->line_AA, config->shape_AA);\n    nk_foreach(cmd, ctx)\n    {\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n        ctx->draw_list.userdata = cmd->userdata;\n#endif\n        switch (cmd->type) {\n        case NK_COMMAND_NOP: break;\n        case NK_COMMAND_SCISSOR: {\n            const struct nk_command_scissor *s = (const struct nk_command_scissor*)cmd;\n            nk_draw_list_add_clip(&ctx->draw_list, nk_rect(s->x, s->y, s->w, s->h));\n        } break;\n        case NK_COMMAND_LINE: {\n            const struct nk_command_line *l = (const struct nk_command_line*)cmd;\n            nk_draw_list_stroke_line(&ctx->draw_list, nk_vec2(l->begin.x, l->begin.y),\n                nk_vec2(l->end.x, l->end.y), l->color, l->line_thickness);\n        } break;\n        case NK_COMMAND_CURVE: {\n            const struct nk_command_curve *q = (const struct nk_command_curve*)cmd;\n            nk_draw_list_stroke_curve(&ctx->draw_list, nk_vec2(q->begin.x, q->begin.y),\n                nk_vec2(q->ctrl[0].x, q->ctrl[0].y), nk_vec2(q->ctrl[1].x,\n                q->ctrl[1].y), nk_vec2(q->end.x, q->end.y), q->color,\n                config->curve_segment_count, q->line_thickness);\n        } break;\n        case NK_COMMAND_RECT: {\n            const struct nk_command_rect *r = (const struct nk_command_rect*)cmd;\n            nk_draw_list_stroke_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),\n                r->color, (float)r->rounding, r->line_thickness);\n        } break;\n        case NK_COMMAND_RECT_FILLED: {\n            const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled*)cmd;\n            nk_draw_list_fill_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),\n                r->color, (float)r->rounding);\n        } break;\n        case NK_COMMAND_RECT_MULTI_COLOR: {\n            const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color*)cmd;\n            nk_draw_list_fill_rect_multi_color(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),\n                r->left, r->top, r->right, r->bottom);\n        } break;\n        case NK_COMMAND_CIRCLE: {\n            const struct nk_command_circle *c = (const struct nk_command_circle*)cmd;\n            nk_draw_list_stroke_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2,\n                (float)c->y + (float)c->h/2), (float)c->w/2, c->color,\n                config->circle_segment_count, c->line_thickness);\n        } break;\n        case NK_COMMAND_CIRCLE_FILLED: {\n            const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;\n            nk_draw_list_fill_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2,\n                (float)c->y + (float)c->h/2), (float)c->w/2, c->color,\n                config->circle_segment_count);\n        } break;\n        case NK_COMMAND_ARC: {\n            const struct nk_command_arc *c = (const struct nk_command_arc*)cmd;\n            nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy));\n            nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r,\n                c->a[0], c->a[1], config->arc_segment_count);\n            nk_draw_list_path_stroke(&ctx->draw_list, c->color, NK_STROKE_CLOSED, c->line_thickness);\n        } break;\n        case NK_COMMAND_ARC_FILLED: {\n            const struct nk_command_arc_filled *c = (const struct nk_command_arc_filled*)cmd;\n            nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy));\n            nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r,\n                c->a[0], c->a[1], config->arc_segment_count);\n            nk_draw_list_path_fill(&ctx->draw_list, c->color);\n        } break;\n        case NK_COMMAND_TRIANGLE: {\n            const struct nk_command_triangle *t = (const struct nk_command_triangle*)cmd;\n            nk_draw_list_stroke_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y),\n                nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color,\n                t->line_thickness);\n        } break;\n        case NK_COMMAND_TRIANGLE_FILLED: {\n            const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled*)cmd;\n            nk_draw_list_fill_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y),\n                nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color);\n        } break;\n        case NK_COMMAND_POLYGON: {\n            int i;\n            const struct nk_command_polygon*p = (const struct nk_command_polygon*)cmd;\n            for (i = 0; i < p->point_count; ++i) {\n                struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);\n                nk_draw_list_path_line_to(&ctx->draw_list, pnt);\n            }\n            nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_CLOSED, p->line_thickness);\n        } break;\n        case NK_COMMAND_POLYGON_FILLED: {\n            int i;\n            const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled*)cmd;\n            for (i = 0; i < p->point_count; ++i) {\n                struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);\n                nk_draw_list_path_line_to(&ctx->draw_list, pnt);\n            }\n            nk_draw_list_path_fill(&ctx->draw_list, p->color);\n        } break;\n        case NK_COMMAND_POLYLINE: {\n            int i;\n            const struct nk_command_polyline *p = (const struct nk_command_polyline*)cmd;\n            for (i = 0; i < p->point_count; ++i) {\n                struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);\n                nk_draw_list_path_line_to(&ctx->draw_list, pnt);\n            }\n            nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_OPEN, p->line_thickness);\n        } break;\n        case NK_COMMAND_TEXT: {\n            const struct nk_command_text *t = (const struct nk_command_text*)cmd;\n            nk_draw_list_add_text(&ctx->draw_list, t->font, nk_rect(t->x, t->y, t->w, t->h),\n                t->string, t->length, t->height, t->foreground);\n        } break;\n        case NK_COMMAND_IMAGE: {\n            const struct nk_command_image *i = (const struct nk_command_image*)cmd;\n            nk_draw_list_add_image(&ctx->draw_list, i->img, nk_rect(i->x, i->y, i->w, i->h), i->col);\n        } break;\n        case NK_COMMAND_CUSTOM: {\n            const struct nk_command_custom *c = (const struct nk_command_custom*)cmd;\n            c->callback(&ctx->draw_list, c->x, c->y, c->w, c->h, c->callback_data);\n        } break;\n        default: break;\n        }\n    }\n    res |= (cmds->needed > cmds->allocated + (cmds->memory.size - cmds->size)) ? NK_CONVERT_COMMAND_BUFFER_FULL: 0;\n    res |= (vertices->needed > vertices->allocated) ? NK_CONVERT_VERTEX_BUFFER_FULL: 0;\n    res |= (elements->needed > elements->allocated) ? NK_CONVERT_ELEMENT_BUFFER_FULL: 0;\n    return res;\n}\nNK_API const struct nk_draw_command*\nnk__draw_begin(const struct nk_context *ctx,\n    const struct nk_buffer *buffer)\n{\n    return nk__draw_list_begin(&ctx->draw_list, buffer);\n}\nNK_API const struct nk_draw_command*\nnk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buffer)\n{\n    return nk__draw_list_end(&ctx->draw_list, buffer);\n}\nNK_API const struct nk_draw_command*\nnk__draw_next(const struct nk_draw_command *cmd,\n    const struct nk_buffer *buffer, const struct nk_context *ctx)\n{\n    return nk__draw_list_next(cmd, buffer, &ctx->draw_list);\n}\n#endif\n\n\n/*  stb_rect_pack.h - v1.01 - public domain - rectangle packing */\n/*  Sean Barrett 2014 */\n/*  */\n/*  Useful for e.g. packing rectangular textures into an atlas. */\n/*  Does not do rotation. */\n/*  */\n/*  Before #including, */\n/*  */\n/*     #define STB_RECT_PACK_IMPLEMENTATION */\n/*  */\n/*  in the file that you want to have the implementation. */\n/*  */\n/*  Not necessarily the awesomest packing method, but better than */\n/*  the totally naive one in stb_truetype (which is primarily what */\n/*  this is meant to replace). */\n/*  */\n/*  Has only had a few tests run, may have issues. */\n/*  */\n/*  More docs to come. */\n/*  */\n/*  No memory allocations; uses qsort() and assert() from stdlib. */\n/*  Can override those by defining STBRP_SORT and STBRP_ASSERT. */\n/*  */\n/*  This library currently uses the Skyline Bottom-Left algorithm. */\n/*  */\n/*  Please note: better rectangle packers are welcome! Please */\n/*  implement them to the same API, but with a different init */\n/*  function. */\n/*  */\n/*  Credits */\n/*  */\n/*   Library */\n/*     Sean Barrett */\n/*   Minor features */\n/*     Martins Mozeiko */\n/*     github:IntellectualKitty */\n/*  */\n/*   Bugfixes / warning fixes */\n/*     Jeremy Jaussaud */\n/*     Fabian Giesen */\n/*  */\n/*  Version history: */\n/*  */\n/*      1.01  (2021-07-11)  always use large rect mode, expose STBRP__MAXVAL in public section */\n/*      1.00  (2019-02-25)  avoid small space waste; gracefully fail too-wide rectangles */\n/*      0.99  (2019-02-07)  warning fixes */\n/*      0.11  (2017-03-03)  return packing success/fail result */\n/*      0.10  (2016-10-25)  remove cast-away-const to avoid warnings */\n/*      0.09  (2016-08-27)  fix compiler warnings */\n/*      0.08  (2015-09-13)  really fix bug with empty rects (w=0 or h=0) */\n/*      0.07  (2015-09-13)  fix bug with empty rects (w=0 or h=0) */\n/*      0.06  (2015-04-15)  added STBRP_SORT to allow replacing qsort */\n/*      0.05:  added STBRP_ASSERT to allow replacing assert */\n/*      0.04:  fixed minor bug in STBRP_LARGE_RECTS support */\n/*      0.01:  initial release */\n/*  */\n/*  LICENSE */\n/*  */\n/*    See end of file for license information. */\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*        INCLUDE SECTION */\n/*  */\n\n#ifndef STB_INCLUDE_STB_RECT_PACK_H\n#define STB_INCLUDE_STB_RECT_PACK_H\n\n#define STB_RECT_PACK_VERSION  1\n\n#ifdef STBRP_STATIC\n#define STBRP_DEF static\n#else\n#define STBRP_DEF extern\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct stbrp_context stbrp_context;\ntypedef struct stbrp_node    stbrp_node;\ntypedef struct stbrp_rect    stbrp_rect;\n\ntypedef int            stbrp_coord;\n\n#define STBRP__MAXVAL  0x7fffffff\n/*  Mostly for internal use, but this is the maximum supported coordinate value. */\n\nSTBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);\n/*  Assign packed locations to rectangles. The rectangles are of type */\n/*  'stbrp_rect' defined below, stored in the array 'rects', and there */\n/*  are 'num_rects' many of them. */\n/*  */\n/*  Rectangles which are successfully packed have the 'was_packed' flag */\n/*  set to a non-zero value and 'x' and 'y' store the minimum location */\n/*  on each axis (i.e. bottom-left in cartesian coordinates, top-left */\n/*  if you imagine y increasing downwards). Rectangles which do not fit */\n/*  have the 'was_packed' flag set to 0. */\n/*  */\n/*  You should not try to access the 'rects' array from another thread */\n/*  while this function is running, as the function temporarily reorders */\n/*  the array while it executes. */\n/*  */\n/*  To pack into another rectangle, you need to call stbrp_init_target */\n/*  again. To continue packing into the same rectangle, you can call */\n/*  this function again. Calling this multiple times with multiple rect */\n/*  arrays will probably produce worse packing results than calling it */\n/*  a single time with the full rectangle array, but the option is */\n/*  available. */\n/*  */\n/*  The function returns 1 if all of the rectangles were successfully */\n/*  packed and 0 otherwise. */\n\nstruct stbrp_rect\n{\n   /*  reserved for your use: */\n   int            id;\n\n   /*  input: */\n   stbrp_coord    w, h;\n\n   /*  output: */\n   stbrp_coord    x, y;\n   int            was_packed;  /*  non-zero if valid packing */\n\n}; /*  16 bytes, nominally */\n\n\nSTBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);\n/*  Initialize a rectangle packer to: */\n/*     pack a rectangle that is 'width' by 'height' in dimensions */\n/*     using temporary storage provided by the array 'nodes', which is 'num_nodes' long */\n/*  */\n/*  You must call this function every time you start packing into a new target. */\n/*  */\n/*  There is no \"shutdown\" function. The 'nodes' memory must stay valid for */\n/*  the following stbrp_pack_rects() call (or calls), but can be freed after */\n/*  the call (or calls) finish. */\n/*  */\n/*  Note: to guarantee best results, either: */\n/*        1. make sure 'num_nodes' >= 'width' */\n/*    or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1' */\n/*  */\n/*  If you don't do either of the above things, widths will be quantized to multiples */\n/*  of small integers to guarantee the algorithm doesn't run out of temporary storage. */\n/*  */\n/*  If you do #2, then the non-quantized algorithm will be used, but the algorithm */\n/*  may run out of temporary storage and be unable to pack some rectangles. */\n\nSTBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);\n/*  Optionally call this function after init but before doing any packing to */\n/*  change the handling of the out-of-temp-memory scenario, described above. */\n/*  If you call init again, this will be reset to the default (false). */\n\n\nSTBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);\n/*  Optionally select which packing heuristic the library should use. Different */\n/*  heuristics will produce better/worse results for different data sets. */\n/*  If you call init again, this will be reset to the default. */\n\nenum\n{\n   STBRP_HEURISTIC_Skyline_default=0,\n   STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,\n   STBRP_HEURISTIC_Skyline_BF_sortHeight\n};\n\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  the details of the following structures don't matter to you, but they must */\n/*  be visible so you can handle the memory allocations for them */\n\nstruct stbrp_node\n{\n   stbrp_coord  x,y;\n   stbrp_node  *next;\n};\n\nstruct stbrp_context\n{\n   int width;\n   int height;\n   int align;\n   int init_mode;\n   int heuristic;\n   int num_nodes;\n   stbrp_node *active_head;\n   stbrp_node *free_head;\n   stbrp_node extra[2]; /*  we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2' */\n};\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*      IMPLEMENTATION SECTION */\n/*  */\n\n#ifdef STB_RECT_PACK_IMPLEMENTATION\n#ifndef STBRP_SORT\n#include <stdlib.h>\n#define STBRP_SORT qsort\n#endif\n\n#ifndef STBRP_ASSERT\n#include <assert.h>\n#define STBRP_ASSERT assert\n#endif\n\n#ifdef _MSC_VER\n#define STBRP__NOTUSED(v)  (void)(v)\n#define STBRP__CDECL       __cdecl\n#else\n#define STBRP__NOTUSED(v)  (void)sizeof(v)\n#define STBRP__CDECL\n#endif\n\nenum\n{\n   STBRP__INIT_skyline = 1\n};\n\nSTBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)\n{\n   switch (context->init_mode) {\n      case STBRP__INIT_skyline:\n         STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);\n         context->heuristic = heuristic;\n         break;\n      default:\n         STBRP_ASSERT(0);\n   }\n}\n\nSTBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)\n{\n   if (allow_out_of_mem)\n      /*  if it's ok to run out of memory, then don't bother aligning them; */\n      /*  this gives better packing, but may fail due to OOM (even though */\n      /*  the rectangles easily fit). @TODO a smarter approach would be to only */\n      /*  quantize once we've hit OOM, then we could get rid of this parameter. */\n      context->align = 1;\n   else {\n      /*  if it's not ok to run out of memory, then quantize the widths */\n      /*  so that num_nodes is always enough nodes. */\n      /*  */\n      /*  I.e. num_nodes * align >= width */\n      /*                   align >= width / num_nodes */\n      /*                   align = ceil(width/num_nodes) */\n\n      context->align = (context->width + context->num_nodes-1) / context->num_nodes;\n   }\n}\n\nSTBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)\n{\n   int i;\n\n   for (i=0; i < num_nodes-1; ++i)\n      nodes[i].next = &nodes[i+1];\n   nodes[i].next = NULL;\n   context->init_mode = STBRP__INIT_skyline;\n   context->heuristic = STBRP_HEURISTIC_Skyline_default;\n   context->free_head = &nodes[0];\n   context->active_head = &context->extra[0];\n   context->width = width;\n   context->height = height;\n   context->num_nodes = num_nodes;\n   stbrp_setup_allow_out_of_mem(context, 0);\n\n   /*  node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly) */\n   context->extra[0].x = 0;\n   context->extra[0].y = 0;\n   context->extra[0].next = &context->extra[1];\n   context->extra[1].x = (stbrp_coord) width;\n   context->extra[1].y = (1<<30);\n   context->extra[1].next = NULL;\n}\n\n/*  find minimum y position if it starts at x1 */\nstatic int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)\n{\n   stbrp_node *node = first;\n   int x1 = x0 + width;\n   int min_y, visited_width, waste_area;\n\n   STBRP__NOTUSED(c);\n\n   STBRP_ASSERT(first->x <= x0);\n\n   #if 0\n   /*  skip in case we're past the node */\n   while (node->next->x <= x0)\n      ++node;\n   #else\n   STBRP_ASSERT(node->next->x > x0); /*  we ended up handling this in the caller for efficiency */\n   #endif\n\n   STBRP_ASSERT(node->x <= x0);\n\n   min_y = 0;\n   waste_area = 0;\n   visited_width = 0;\n   while (node->x < x1) {\n      if (node->y > min_y) {\n         /*  raise min_y higher. */\n         /*  we've accounted for all waste up to min_y, */\n         /*  but we'll now add more waste for everything we've visited */\n         waste_area += visited_width * (node->y - min_y);\n         min_y = node->y;\n         /*  the first time through, visited_width might be reduced */\n         if (node->x < x0)\n            visited_width += node->next->x - x0;\n         else\n            visited_width += node->next->x - node->x;\n      } else {\n         /*  add waste area */\n         int under_width = node->next->x - node->x;\n         if (under_width + visited_width > width)\n            under_width = width - visited_width;\n         waste_area += under_width * (min_y - node->y);\n         visited_width += under_width;\n      }\n      node = node->next;\n   }\n\n   *pwaste = waste_area;\n   return min_y;\n}\n\ntypedef struct\n{\n   int x,y;\n   stbrp_node **prev_link;\n} stbrp__findresult;\n\nstatic stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)\n{\n   int best_waste = (1<<30), best_x, best_y = (1 << 30);\n   stbrp__findresult fr;\n   stbrp_node **prev, *node, *tail, **best = NULL;\n\n   /*  align to multiple of c->align */\n   width = (width + c->align - 1);\n   width -= width % c->align;\n   STBRP_ASSERT(width % c->align == 0);\n\n   /*  if it can't possibly fit, bail immediately */\n   if (width > c->width || height > c->height) {\n      fr.prev_link = NULL;\n      fr.x = fr.y = 0;\n      return fr;\n   }\n\n   node = c->active_head;\n   prev = &c->active_head;\n   while (node->x + width <= c->width) {\n      int y,waste;\n      y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);\n      if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { /*  actually just want to test BL */\n         /*  bottom left */\n         if (y < best_y) {\n            best_y = y;\n            best = prev;\n         }\n      } else {\n         /*  best-fit */\n         if (y + height <= c->height) {\n            /*  can only use it if it first vertically */\n            if (y < best_y || (y == best_y && waste < best_waste)) {\n               best_y = y;\n               best_waste = waste;\n               best = prev;\n            }\n         }\n      }\n      prev = &node->next;\n      node = node->next;\n   }\n\n   best_x = (best == NULL) ? 0 : (*best)->x;\n\n   /*  if doing best-fit (BF), we also have to try aligning right edge to each node position */\n   /*  */\n   /*  e.g, if fitting */\n   /*  */\n   /*      ____________________ */\n   /*     |____________________| */\n   /*  */\n   /*             into */\n   /*  */\n   /*    |                         | */\n   /*    |             ____________| */\n   /*    |____________| */\n   /*  */\n   /*  then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned */\n   /*  */\n   /*  This makes BF take about 2x the time */\n\n   if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {\n      tail = c->active_head;\n      node = c->active_head;\n      prev = &c->active_head;\n      /*  find first node that's admissible */\n      while (tail->x < width)\n         tail = tail->next;\n      while (tail) {\n         int xpos = tail->x - width;\n         int y,waste;\n         STBRP_ASSERT(xpos >= 0);\n         /*  find the left position that matches this */\n         while (node->next->x <= xpos) {\n            prev = &node->next;\n            node = node->next;\n         }\n         STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);\n         y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);\n         if (y + height <= c->height) {\n            if (y <= best_y) {\n               if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {\n                  best_x = xpos;\n                  STBRP_ASSERT(y <= best_y);\n                  best_y = y;\n                  best_waste = waste;\n                  best = prev;\n               }\n            }\n         }\n         tail = tail->next;\n      }\n   }\n\n   fr.prev_link = best;\n   fr.x = best_x;\n   fr.y = best_y;\n   return fr;\n}\n\nstatic stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)\n{\n   /*  find best position according to heuristic */\n   stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);\n   stbrp_node *node, *cur;\n\n   /*  bail if: */\n   /*     1. it failed */\n   /*     2. the best node doesn't fit (we don't always check this) */\n   /*     3. we're out of memory */\n   if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {\n      res.prev_link = NULL;\n      return res;\n   }\n\n   /*  on success, create new node */\n   node = context->free_head;\n   node->x = (stbrp_coord) res.x;\n   node->y = (stbrp_coord) (res.y + height);\n\n   context->free_head = node->next;\n\n   /*  insert the new node into the right starting point, and */\n   /*  let 'cur' point to the remaining nodes needing to be */\n   /*  stitched back in */\n\n   cur = *res.prev_link;\n   if (cur->x < res.x) {\n      /*  preserve the existing one, so start testing with the next one */\n      stbrp_node *next = cur->next;\n      cur->next = node;\n      cur = next;\n   } else {\n      *res.prev_link = node;\n   }\n\n   /*  from here, traverse cur and free the nodes, until we get to one */\n   /*  that shouldn't be freed */\n   while (cur->next && cur->next->x <= res.x + width) {\n      stbrp_node *next = cur->next;\n      /*  move the current node to the free list */\n      cur->next = context->free_head;\n      context->free_head = cur;\n      cur = next;\n   }\n\n   /*  stitch the list back in */\n   node->next = cur;\n\n   if (cur->x < res.x + width)\n      cur->x = (stbrp_coord) (res.x + width);\n\n#ifdef _DEBUG\n   cur = context->active_head;\n   while (cur->x < context->width) {\n      STBRP_ASSERT(cur->x < cur->next->x);\n      cur = cur->next;\n   }\n   STBRP_ASSERT(cur->next == NULL);\n\n   {\n      int count=0;\n      cur = context->active_head;\n      while (cur) {\n         cur = cur->next;\n         ++count;\n      }\n      cur = context->free_head;\n      while (cur) {\n         cur = cur->next;\n         ++count;\n      }\n      STBRP_ASSERT(count == context->num_nodes+2);\n   }\n#endif\n\n   return res;\n}\n\nstatic int STBRP__CDECL rect_height_compare(const void *a, const void *b)\n{\n   const stbrp_rect *p = (const stbrp_rect *) a;\n   const stbrp_rect *q = (const stbrp_rect *) b;\n   if (p->h > q->h)\n      return -1;\n   if (p->h < q->h)\n      return  1;\n   return (p->w > q->w) ? -1 : (p->w < q->w);\n}\n\nstatic int STBRP__CDECL rect_original_order(const void *a, const void *b)\n{\n   const stbrp_rect *p = (const stbrp_rect *) a;\n   const stbrp_rect *q = (const stbrp_rect *) b;\n   return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);\n}\n\nSTBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)\n{\n   int i, all_rects_packed = 1;\n\n   /*  we use the 'was_packed' field internally to allow sorting/unsorting */\n   for (i=0; i < num_rects; ++i) {\n      rects[i].was_packed = i;\n   }\n\n   /*  sort according to heuristic */\n   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);\n\n   for (i=0; i < num_rects; ++i) {\n      if (rects[i].w == 0 || rects[i].h == 0) {\n         rects[i].x = rects[i].y = 0;  /*  empty rect needs no space */\n      } else {\n         stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);\n         if (fr.prev_link) {\n            rects[i].x = (stbrp_coord) fr.x;\n            rects[i].y = (stbrp_coord) fr.y;\n         } else {\n            rects[i].x = rects[i].y = STBRP__MAXVAL;\n         }\n      }\n   }\n\n   /*  unsort */\n   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);\n\n   /*  set was_packed flags and all_rects_packed status */\n   for (i=0; i < num_rects; ++i) {\n      rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);\n      if (!rects[i].was_packed)\n         all_rects_packed = 0;\n   }\n\n   /*  return the all_rects_packed status */\n   return all_rects_packed;\n}\n#endif\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n\n/*  stb_truetype.h - v1.26 - public domain */\n/*  authored from 2009-2021 by Sean Barrett / RAD Game Tools */\n/*  */\n/*  ======================================================================= */\n/*  */\n/*     NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES */\n/*  */\n/*  This library does no range checking of the offsets found in the file, */\n/*  meaning an attacker can use it to read arbitrary memory. */\n/*  */\n/*  ======================================================================= */\n/*  */\n/*    This library processes TrueType files: */\n/*         parse files */\n/*         extract glyph metrics */\n/*         extract glyph shapes */\n/*         render glyphs to one-channel bitmaps with antialiasing (box filter) */\n/*         render glyphs to one-channel SDF bitmaps (signed-distance field/function) */\n/*  */\n/*    Todo: */\n/*         non-MS cmaps */\n/*         crashproof on bad data */\n/*         hinting? (no longer patented) */\n/*         cleartype-style AA? */\n/*         optimize: use simple memory allocator for intermediates */\n/*         optimize: build edge-list directly from curves */\n/*         optimize: rasterize directly from curves? */\n/*  */\n/*  ADDITIONAL CONTRIBUTORS */\n/*  */\n/*    Mikko Mononen: compound shape support, more cmap formats */\n/*    Tor Andersson: kerning, subpixel rendering */\n/*    Dougall Johnson: OpenType / Type 2 font handling */\n/*    Daniel Ribeiro Maciel: basic GPOS-based kerning */\n/*  */\n/*    Misc other: */\n/*        Ryan Gordon */\n/*        Simon Glass */\n/*        github:IntellectualKitty */\n/*        Imanol Celaya */\n/*        Daniel Ribeiro Maciel */\n/*  */\n/*    Bug/warning reports/fixes: */\n/*        \"Zer\" on mollyrocket       Fabian \"ryg\" Giesen   github:NiLuJe */\n/*        Cass Everitt               Martins Mozeiko       github:aloucks */\n/*        stoiko (Haemimont Games)   Cap Petschulat        github:oyvindjam */\n/*        Brian Hook                 Omar Cornut           github:vassvik */\n/*        Walter van Niftrik         Ryan Griege */\n/*        David Gow                  Peter LaValle */\n/*        David Given                Sergey Popov */\n/*        Ivan-Assen Ivanov          Giumo X. Clanjor */\n/*        Anthony Pesch              Higor Euripedes */\n/*        Johan Duparc               Thomas Fields */\n/*        Hou Qiming                 Derek Vinyard */\n/*        Rob Loach                  Cort Stratton */\n/*        Kenney Phillis Jr.         Brian Costabile */\n/*        Ken Voskuil (kaesve) */\n/*  */\n/*  VERSION HISTORY */\n/*  */\n/*    1.26 (2021-08-28) fix broken rasterizer */\n/*    1.25 (2021-07-11) many fixes */\n/*    1.24 (2020-02-05) fix warning */\n/*    1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) */\n/*    1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined */\n/*    1.21 (2019-02-25) fix warning */\n/*    1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() */\n/*    1.19 (2018-02-11) GPOS kerning, STBTT_fmod */\n/*    1.18 (2018-01-29) add missing function */\n/*    1.17 (2017-07-23) make more arguments const; doc fix */\n/*    1.16 (2017-07-12) SDF support */\n/*    1.15 (2017-03-03) make more arguments const */\n/*    1.14 (2017-01-16) num-fonts-in-TTC function */\n/*    1.13 (2017-01-02) support OpenType fonts, certain Apple fonts */\n/*    1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual */\n/*    1.11 (2016-04-02) fix unused-variable warning */\n/*    1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef */\n/*    1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly */\n/*    1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges */\n/*    1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; */\n/*                      variant PackFontRanges to pack and render in separate phases; */\n/*                      fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); */\n/*                      fixed an assert() bug in the new rasterizer */\n/*                      replace assert() with STBTT_assert() in new rasterizer */\n/*  */\n/*    Full history can be found at the end of this file. */\n/*  */\n/*  LICENSE */\n/*  */\n/*    See end of file for license information. */\n/*  */\n/*  USAGE */\n/*  */\n/*    Include this file in whatever places need to refer to it. In ONE C/C++ */\n/*    file, write: */\n/*       #define STB_TRUETYPE_IMPLEMENTATION */\n/*    before the #include of this file. This expands out the actual */\n/*    implementation into that C/C++ file. */\n/*  */\n/*    To make the implementation private to the file that generates the implementation, */\n/*       #define STBTT_STATIC */\n/*  */\n/*    Simple 3D API (don't ship this, but it's fine for tools and quick start) */\n/*            stbtt_BakeFontBitmap()               -- bake a font to a bitmap for use as texture */\n/*            stbtt_GetBakedQuad()                 -- compute quad to draw for a given char */\n/*  */\n/*    Improved 3D API (more shippable): */\n/*            #include \"stb_rect_pack.h\"           -- optional, but you really want it */\n/*            stbtt_PackBegin() */\n/*            stbtt_PackSetOversampling()          -- for improved quality on small fonts */\n/*            stbtt_PackFontRanges()               -- pack and renders */\n/*            stbtt_PackEnd() */\n/*            stbtt_GetPackedQuad() */\n/*  */\n/*    \"Load\" a font file from a memory buffer (you have to keep the buffer loaded) */\n/*            stbtt_InitFont() */\n/*            stbtt_GetFontOffsetForIndex()        -- indexing for TTC font collections */\n/*            stbtt_GetNumberOfFonts()             -- number of fonts for TTC font collections */\n/*  */\n/*    Render a unicode codepoint to a bitmap */\n/*            stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap */\n/*            stbtt_MakeCodepointBitmap()          -- renders into bitmap you provide */\n/*            stbtt_GetCodepointBitmapBox()        -- how big the bitmap must be */\n/*  */\n/*    Character advance/positioning */\n/*            stbtt_GetCodepointHMetrics() */\n/*            stbtt_GetFontVMetrics() */\n/*            stbtt_GetFontVMetricsOS2() */\n/*            stbtt_GetCodepointKernAdvance() */\n/*  */\n/*    Starting with version 1.06, the rasterizer was replaced with a new, */\n/*    faster and generally-more-precise rasterizer. The new rasterizer more */\n/*    accurately measures pixel coverage for anti-aliasing, except in the case */\n/*    where multiple shapes overlap, in which case it overestimates the AA pixel */\n/*    coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If */\n/*    this turns out to be a problem, you can re-enable the old rasterizer with */\n/*         #define STBTT_RASTERIZER_VERSION 1 */\n/*    which will incur about a 15% speed hit. */\n/*  */\n/*  ADDITIONAL DOCUMENTATION */\n/*  */\n/*    Immediately after this block comment are a series of sample programs. */\n/*  */\n/*    After the sample programs is the \"header file\" section. This section */\n/*    includes documentation for each API function. */\n/*  */\n/*    Some important concepts to understand to use this library: */\n/*  */\n/*       Codepoint */\n/*          Characters are defined by unicode codepoints, e.g. 65 is */\n/*          uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is */\n/*          the hiragana for \"ma\". */\n/*  */\n/*       Glyph */\n/*          A visual character shape (every codepoint is rendered as */\n/*          some glyph) */\n/*  */\n/*       Glyph index */\n/*          A font-specific integer ID representing a glyph */\n/*  */\n/*       Baseline */\n/*          Glyph shapes are defined relative to a baseline, which is the */\n/*          bottom of uppercase characters. Characters extend both above */\n/*          and below the baseline. */\n/*  */\n/*       Current Point */\n/*          As you draw text to the screen, you keep track of a \"current point\" */\n/*          which is the origin of each character. The current point's vertical */\n/*          position is the baseline. Even \"baked fonts\" use this model. */\n/*  */\n/*       Vertical Font Metrics */\n/*          The vertical qualities of the font, used to vertically position */\n/*          and space the characters. See docs for stbtt_GetFontVMetrics. */\n/*  */\n/*       Font Size in Pixels or Points */\n/*          The preferred interface for specifying font sizes in stb_truetype */\n/*          is to specify how tall the font's vertical extent should be in pixels. */\n/*          If that sounds good enough, skip the next paragraph. */\n/*  */\n/*          Most font APIs instead use \"points\", which are a common typographic */\n/*          measurement for describing font size, defined as 72 points per inch. */\n/*          stb_truetype provides a point API for compatibility. However, true */\n/*          \"per inch\" conventions don't make much sense on computer displays */\n/*          since different monitors have different number of pixels per */\n/*          inch. For example, Windows traditionally uses a convention that */\n/*          there are 96 pixels per inch, thus making 'inch' measurements have */\n/*          nothing to do with inches, and thus effectively defining a point to */\n/*          be 1.333 pixels. Additionally, the TrueType font data provides */\n/*          an explicit scale factor to scale a given font's glyphs to points, */\n/*          but the author has observed that this scale factor is often wrong */\n/*          for non-commercial fonts, thus making fonts scaled in points */\n/*          according to the TrueType spec incoherently sized in practice. */\n/*  */\n/*  DETAILED USAGE: */\n/*  */\n/*   Scale: */\n/*     Select how high you want the font to be, in points or pixels. */\n/*     Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute */\n/*     a scale factor SF that will be used by all other functions. */\n/*  */\n/*   Baseline: */\n/*     You need to select a y-coordinate that is the baseline of where */\n/*     your text will appear. Call GetFontBoundingBox to get the baseline-relative */\n/*     bounding box for all characters. SF*-y0 will be the distance in pixels */\n/*     that the worst-case character could extend above the baseline, so if */\n/*     you want the top edge of characters to appear at the top of the */\n/*     screen where y=0, then you would set the baseline to SF*-y0. */\n/*  */\n/*   Current point: */\n/*     Set the current point where the first character will appear. The */\n/*     first character could extend left of the current point; this is font */\n/*     dependent. You can either choose a current point that is the leftmost */\n/*     point and hope, or add some padding, or check the bounding box or */\n/*     left-side-bearing of the first character to be displayed and set */\n/*     the current point based on that. */\n/*  */\n/*   Displaying a character: */\n/*     Compute the bounding box of the character. It will contain signed values */\n/*     relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1, */\n/*     then the character should be displayed in the rectangle from */\n/*     <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1). */\n/*  */\n/*   Advancing for the next character: */\n/*     Call GlyphHMetrics, and compute 'current_point += SF * advance'. */\n/*  */\n/*  */\n/*  ADVANCED USAGE */\n/*  */\n/*    Quality: */\n/*  */\n/*     - Use the functions with Subpixel at the end to allow your characters */\n/*       to have subpixel positioning. Since the font is anti-aliased, not */\n/*       hinted, this is very import for quality. (This is not possible with */\n/*       baked fonts.) */\n/*  */\n/*     - Kerning is now supported, and if you're supporting subpixel rendering */\n/*       then kerning is worth using to give your text a polished look. */\n/*  */\n/*    Performance: */\n/*  */\n/*     - Convert Unicode codepoints to glyph indexes and operate on the glyphs; */\n/*       if you don't do this, stb_truetype is forced to do the conversion on */\n/*       every call. */\n/*  */\n/*     - There are a lot of memory allocations. We should modify it to take */\n/*       a temp buffer and allocate from the temp buffer (without freeing), */\n/*       should help performance a lot. */\n/*  */\n/*  NOTES */\n/*  */\n/*    The system uses the raw data found in the .ttf file without changing it */\n/*    and without building auxiliary data structures. This is a bit inefficient */\n/*    on little-endian systems (the data is big-endian), but assuming you're */\n/*    caching the bitmaps or glyph shapes this shouldn't be a big deal. */\n/*  */\n/*    It appears to be very hard to programmatically determine what font a */\n/*    given file is in a general way. I provide an API for this, but I don't */\n/*    recommend it. */\n/*  */\n/*  */\n/*  PERFORMANCE MEASUREMENTS FOR 1.06: */\n/*  */\n/*                       32-bit     64-bit */\n/*    Previous release:  8.83 s     7.68 s */\n/*    Pool allocations:  7.72 s     6.34 s */\n/*    Inline sort     :  6.54 s     5.65 s */\n/*    New rasterizer  :  5.63 s     5.00 s */\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/* //////////////////////////////////////////////////////////////////////////// */\n/* // */\n/* //  SAMPLE PROGRAMS */\n/* // */\n/*  */\n/*   Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless. */\n/*   See \"tests/truetype_demo_win32.c\" for a complete version. */\n#if 0\n#define STB_TRUETYPE_IMPLEMENTATION  /*  force following include to generate implementation */\n#include \"stb_truetype.h\"\n\nunsigned char ttf_buffer[1<<20];\nunsigned char temp_bitmap[512*512];\n\nstbtt_bakedchar cdata[96]; /*  ASCII 32..126 is 95 glyphs */\nGLuint ftex;\n\nvoid my_stbtt_initfont(void)\n{\n   fread(ttf_buffer, 1, 1<<20, fopen(\"c:/windows/fonts/times.ttf\", \"rb\"));\n   stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); /*  no guarantee this fits! */\n   /*  can free ttf_buffer at this point */\n   glGenTextures(1, &ftex);\n   glBindTexture(GL_TEXTURE_2D, ftex);\n   glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);\n   /*  can free temp_bitmap at this point */\n   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n}\n\nvoid my_stbtt_print(float x, float y, char *text)\n{\n   /*  assume orthographic projection with units = screen pixels, origin at top left */\n   glEnable(GL_BLEND);\n   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n   glEnable(GL_TEXTURE_2D);\n   glBindTexture(GL_TEXTURE_2D, ftex);\n   glBegin(GL_QUADS);\n   while (*text) {\n      if (*text >= 32 && *text < 128) {\n         stbtt_aligned_quad q;\n         stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);/* 1=opengl & d3d10+,0=d3d9 */\n         glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);\n         glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);\n         glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);\n         glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);\n      }\n      ++text;\n   }\n   glEnd();\n}\n#endif\n/*  */\n/*  */\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  Complete program (this compiles): get a single bitmap, print as ASCII art */\n/*  */\n#if 0\n#include <stdio.h>\n#define STB_TRUETYPE_IMPLEMENTATION  /*  force following include to generate implementation */\n#include \"stb_truetype.h\"\n\nchar ttf_buffer[1<<25];\n\nint main(int argc, char **argv)\n{\n   stbtt_fontinfo font;\n   unsigned char *bitmap;\n   int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);\n\n   fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : \"c:/windows/fonts/arialbd.ttf\", \"rb\"));\n\n   stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));\n   bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);\n\n   for (j=0; j < h; ++j) {\n      for (i=0; i < w; ++i)\n         putchar(\" .:ioVM@\"[bitmap[j*w+i]>>5]);\n      putchar('\\n');\n   }\n   return 0;\n}\n#endif\n/*  */\n/*  Output: */\n/*  */\n/*      .ii. */\n/*     @@@@@@. */\n/*    V@Mio@@o */\n/*    :i.  V@V */\n/*      :oM@@M */\n/*    :@@@MM@M */\n/*    @@o  o@M */\n/*   :@@.  M@M */\n/*    @@@o@@@@ */\n/*    :M@@V:@@. */\n/*  */\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  Complete program: print \"Hello World!\" banner, with bugs */\n/*  */\n#if 0\nchar buffer[24<<20];\nunsigned char screen[20][79];\n\nint main(int arg, char **argv)\n{\n   stbtt_fontinfo font;\n   int i,j,ascent,baseline,ch=0;\n   float scale, xpos=2; /*  leave a little padding in case the character extends left */\n   char *text = \"Heljo World!\"; /*  intentionally misspelled to show 'lj' brokenness */\n\n   fread(buffer, 1, 1000000, fopen(\"c:/windows/fonts/arialbd.ttf\", \"rb\"));\n   stbtt_InitFont(&font, buffer, 0);\n\n   scale = stbtt_ScaleForPixelHeight(&font, 15);\n   stbtt_GetFontVMetrics(&font, &ascent,0,0);\n   baseline = (int) (ascent*scale);\n\n   while (text[ch]) {\n      int advance,lsb,x0,y0,x1,y1;\n      float x_shift = xpos - (float) floor(xpos);\n      stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);\n      stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);\n      stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);\n      /*  note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong */\n      /*  because this API is really for baking character bitmaps into textures. if you want to render */\n      /*  a sequence of characters, you really need to render each bitmap to a temp buffer, then */\n      /*  \"alpha blend\" that into the working buffer */\n      xpos += (advance * scale);\n      if (text[ch+1])\n         xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);\n      ++ch;\n   }\n\n   for (j=0; j < 20; ++j) {\n      for (i=0; i < 78; ++i)\n         putchar(\" .:ioVM@\"[screen[j][i]>>5]);\n      putchar('\\n');\n   }\n\n   return 0;\n}\n#endif\n\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/* //////////////////////////////////////////////////////////////////////////// */\n/* // */\n/* //   INTEGRATION WITH YOUR CODEBASE */\n/* // */\n/* //   The following sections allow you to supply alternate definitions */\n/* //   of C library functions used by stb_truetype, e.g. if you don't */\n/* //   link with the C runtime library. */\n\n#ifdef STB_TRUETYPE_IMPLEMENTATION\n   /*  #define your own (u)stbtt_int8/16/32 before including to override this */\n   #ifndef stbtt_uint8\n   typedef unsigned char   stbtt_uint8;\n   typedef signed   char   stbtt_int8;\n   typedef unsigned short  stbtt_uint16;\n   typedef signed   short  stbtt_int16;\n   typedef unsigned int    stbtt_uint32;\n   typedef signed   int    stbtt_int32;\n   #endif\n\n   typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];\n   typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];\n\n   /*  e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h */\n   #ifndef STBTT_ifloor\n   #include <math.h>\n   #define STBTT_ifloor(x)   ((int) floor(x))\n   #define STBTT_iceil(x)    ((int) ceil(x))\n   #endif\n\n   #ifndef STBTT_sqrt\n   #include <math.h>\n   #define STBTT_sqrt(x)      sqrt(x)\n   #define STBTT_pow(x,y)     pow(x,y)\n   #endif\n\n   #ifndef STBTT_fmod\n   #include <math.h>\n   #define STBTT_fmod(x,y)    fmod(x,y)\n   #endif\n\n   #ifndef STBTT_cos\n   #include <math.h>\n   #define STBTT_cos(x)       cos(x)\n   #define STBTT_acos(x)      acos(x)\n   #endif\n\n   #ifndef STBTT_fabs\n   #include <math.h>\n   #define STBTT_fabs(x)      fabs(x)\n   #endif\n\n   /*  #define your own functions \"STBTT_malloc\" / \"STBTT_free\" to avoid malloc.h */\n   #ifndef STBTT_malloc\n   #include <stdlib.h>\n   #define STBTT_malloc(x,u)  ((void)(u),malloc(x))\n   #define STBTT_free(x,u)    ((void)(u),free(x))\n   #endif\n\n   #ifndef STBTT_assert\n   #include <assert.h>\n   #define STBTT_assert(x)    assert(x)\n   #endif\n\n   #ifndef STBTT_strlen\n   #include <string.h>\n   #define STBTT_strlen(x)    strlen(x)\n   #endif\n\n   #ifndef STBTT_memcpy\n   #include <string.h>\n   #define STBTT_memcpy       memcpy\n   #define STBTT_memset       memset\n   #endif\n#endif\n\n/* ///////////////////////////////////////////////////////////////////////////// */\n/* ///////////////////////////////////////////////////////////////////////////// */\n/* // */\n/* //   INTERFACE */\n/* // */\n/* // */\n\n#ifndef __STB_INCLUDE_STB_TRUETYPE_H__\n#define __STB_INCLUDE_STB_TRUETYPE_H__\n\n#ifdef STBTT_STATIC\n#define STBTT_DEF static\n#else\n#define STBTT_DEF extern\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n/*  private structure */\ntypedef struct\n{\n   unsigned char *data;\n   int cursor;\n   int size;\n} stbtt__buf;\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  TEXTURE BAKING API */\n/*  */\n/*  If you use this API, you only have to call two functions ever. */\n/*  */\n\ntypedef struct\n{\n   unsigned short x0,y0,x1,y1; /*  coordinates of bbox in bitmap */\n   float xoff,yoff,xadvance;\n} stbtt_bakedchar;\n\nSTBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  /*  font location (use offset=0 for plain .ttf) */\n                                float pixel_height,                     /*  height of font in pixels */\n                                unsigned char *pixels, int pw, int ph,  /*  bitmap to be filled in */\n                                int first_char, int num_chars,          /*  characters to bake */\n                                stbtt_bakedchar *chardata);             /*  you allocate this, it's num_chars long */\n/*  if return is positive, the first unused row of the bitmap */\n/*  if return is negative, returns the negative of the number of characters that fit */\n/*  if return is 0, no characters fit and no rows were used */\n/*  This uses a very crappy packing. */\n\ntypedef struct\n{\n   float x0,y0,s0,t0; /*  top-left */\n   float x1,y1,s1,t1; /*  bottom-right */\n} stbtt_aligned_quad;\n\nSTBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph,  /*  same data as above */\n                               int char_index,             /*  character to display */\n                               float *xpos, float *ypos,   /*  pointers to current position in screen pixel space */\n                               stbtt_aligned_quad *q,      /*  output: quad to draw */\n                               int opengl_fillrule);       /*  true if opengl fill rule; false if DX9 or earlier */\n/*  Call GetBakedQuad with char_index = 'character - first_char', and it */\n/*  creates the quad you need to draw and advances the current position. */\n/*  */\n/*  The coordinate system used assumes y increases downwards. */\n/*  */\n/*  Characters will extend both above and below the current position; */\n/*  see discussion of \"BASELINE\" above. */\n/*  */\n/*  It's inefficient; you might want to c&p it and optimize it. */\n\nSTBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);\n/*  Query the font vertical metrics without having to create a font first. */\n\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  NEW TEXTURE BAKING API */\n/*  */\n/*  This provides options for packing multiple fonts into one atlas, not */\n/*  perfectly but better than nothing. */\n\ntypedef struct\n{\n   unsigned short x0,y0,x1,y1; /*  coordinates of bbox in bitmap */\n   float xoff,yoff,xadvance;\n   float xoff2,yoff2;\n} stbtt_packedchar;\n\ntypedef struct stbtt_pack_context stbtt_pack_context;\ntypedef struct stbtt_fontinfo stbtt_fontinfo;\n#ifndef STB_RECT_PACK_VERSION\ntypedef struct stbrp_rect stbrp_rect;\n#endif\n\nSTBTT_DEF int  stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);\n/*  Initializes a packing context stored in the passed-in stbtt_pack_context. */\n/*  Future calls using this context will pack characters into the bitmap passed */\n/*  in here: a 1-channel bitmap that is width * height. stride_in_bytes is */\n/*  the distance from one row to the next (or 0 to mean they are packed tightly */\n/*  together). \"padding\" is the amount of padding to leave between each */\n/*  character (normally you want '1' for bitmaps you'll use as textures with */\n/*  bilinear filtering). */\n/*  */\n/*  Returns 0 on failure, 1 on success. */\n\nSTBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc);\n/*  Cleans up the packing context and frees all memory. */\n\n#define STBTT_POINT_SIZE(x)   (-(x))\n\nSTBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,\n                                int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);\n/*  Creates character bitmaps from the font_index'th font found in fontdata (use */\n/*  font_index=0 if you don't know what that is). It creates num_chars_in_range */\n/*  bitmaps for characters with unicode values starting at first_unicode_char_in_range */\n/*  and increasing. Data for how to render them is stored in chardata_for_range; */\n/*  pass these to stbtt_GetPackedQuad to get back renderable quads. */\n/*  */\n/*  font_size is the full height of the character from ascender to descender, */\n/*  as computed by stbtt_ScaleForPixelHeight. To use a point size as computed */\n/*  by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE() */\n/*  and pass that result as 'font_size': */\n/*        ...,                  20 , ... // font max minus min y is 20 pixels tall */\n/*        ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall */\n\ntypedef struct\n{\n   float font_size;\n   int first_unicode_codepoint_in_range;  /*  if non-zero, then the chars are continuous, and this is the first codepoint */\n   int *array_of_unicode_codepoints;       /*  if non-zero, then this is an array of unicode codepoints */\n   int num_chars;\n   stbtt_packedchar *chardata_for_range; /*  output */\n   unsigned char h_oversample, v_oversample; /*  don't set these, they're used internally */\n} stbtt_pack_range;\n\nSTBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);\n/*  Creates character bitmaps from multiple ranges of characters stored in */\n/*  ranges. This will usually create a better-packed bitmap than multiple */\n/*  calls to stbtt_PackFontRange. Note that you can call this multiple */\n/*  times within a single PackBegin/PackEnd. */\n\nSTBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);\n/*  Oversampling a font increases the quality by allowing higher-quality subpixel */\n/*  positioning, and is especially valuable at smaller text sizes. */\n/*  */\n/*  This function sets the amount of oversampling for all following calls to */\n/*  stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given */\n/*  pack context. The default (no oversampling) is achieved by h_oversample=1 */\n/*  and v_oversample=1. The total number of pixels required is */\n/*  h_oversample*v_oversample larger than the default; for example, 2x2 */\n/*  oversampling requires 4x the storage of 1x1. For best results, render */\n/*  oversampled textures with bilinear filtering. Look at the readme in */\n/*  stb/tests/oversample for information about oversampled fonts */\n/*  */\n/*  To use with PackFontRangesGather etc., you must set it before calls */\n/*  call to PackFontRangesGatherRects. */\n\nSTBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);\n/*  If skip != 0, this tells stb_truetype to skip any codepoints for which */\n/*  there is no corresponding glyph. If skip=0, which is the default, then */\n/*  codepoints without a glyph recived the font's \"missing character\" glyph, */\n/*  typically an empty box by convention. */\n\nSTBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph,  /*  same data as above */\n                               int char_index,             /*  character to display */\n                               float *xpos, float *ypos,   /*  pointers to current position in screen pixel space */\n                               stbtt_aligned_quad *q,      /*  output: quad to draw */\n                               int align_to_integer);\n\nSTBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);\nSTBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);\nSTBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);\n/*  Calling these functions in sequence is roughly equivalent to calling */\n/*  stbtt_PackFontRanges(). If you more control over the packing of multiple */\n/*  fonts, or if you want to pack custom data into a font texture, take a look */\n/*  at the source to of stbtt_PackFontRanges() and create a custom version */\n/*  using these functions, e.g. call GatherRects multiple times, */\n/*  building up a single array of rects, then call PackRects once, */\n/*  then call RenderIntoRects repeatedly. This may result in a */\n/*  better packing than calling PackFontRanges multiple times */\n/*  (or it may not). */\n\n/*  this is an opaque structure that you shouldn't mess with which holds */\n/*  all the context needed from PackBegin to PackEnd. */\nstruct stbtt_pack_context {\n   void *user_allocator_context;\n   void *pack_info;\n   int   width;\n   int   height;\n   int   stride_in_bytes;\n   int   padding;\n   int   skip_missing;\n   unsigned int   h_oversample, v_oversample;\n   unsigned char *pixels;\n   void  *nodes;\n};\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  FONT LOADING */\n/*  */\n/*  */\n\nSTBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);\n/*  This function will determine the number of fonts in a font file.  TrueType */\n/*  collection (.ttc) files may contain multiple fonts, while TrueType font */\n/*  (.ttf) files only contain one font. The number of fonts can be used for */\n/*  indexing with the previous function where the index is between zero and one */\n/*  less than the total fonts. If an error occurs, -1 is returned. */\n\nSTBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);\n/*  Each .ttf/.ttc file may have more than one font. Each font has a sequential */\n/*  index number starting from 0. Call this function to get the font offset for */\n/*  a given index; it returns -1 if the index is out of range. A regular .ttf */\n/*  file will only define one font and it always be at offset 0, so it will */\n/*  return '0' for index 0, and -1 for all other indices. */\n\n/*  The following structure is defined publicly so you can declare one on */\n/*  the stack or as a global or etc, but you should treat it as opaque. */\nstruct stbtt_fontinfo\n{\n   void           * userdata;\n   unsigned char  * data;              /*  pointer to .ttf file */\n   int              fontstart;         /*  offset of start of font */\n\n   int numGlyphs;                     /*  number of glyphs, needed for range checking */\n\n   int loca,head,glyf,hhea,hmtx,kern,gpos,svg; /*  table locations as offset from start of .ttf */\n   int index_map;                     /*  a cmap mapping for our chosen character encoding */\n   int indexToLocFormat;              /*  format needed to map from glyph index to glyph */\n\n   stbtt__buf cff;                    /*  cff font data */\n   stbtt__buf charstrings;            /*  the charstring index */\n   stbtt__buf gsubrs;                 /*  global charstring subroutines index */\n   stbtt__buf subrs;                  /*  private charstring subroutines index */\n   stbtt__buf fontdicts;              /*  array of font dicts */\n   stbtt__buf fdselect;               /*  map from glyph to fontdict */\n};\n\nSTBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);\n/*  Given an offset into the file that defines a font, this function builds */\n/*  the necessary cached info for the rest of the system. You must allocate */\n/*  the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't */\n/*  need to do anything special to free it, because the contents are pure */\n/*  value data with no additional data structures. Returns 0 on failure. */\n\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  CHARACTER TO GLYPH-INDEX CONVERSIOn */\n\nSTBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);\n/*  If you're going to perform multiple operations on the same character */\n/*  and you want a speed-up, call this function with the character you're */\n/*  going to process, then use glyph-based functions instead of the */\n/*  codepoint-based functions. */\n/*  Returns 0 if the character codepoint is not defined in the font. */\n\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  CHARACTER PROPERTIES */\n/*  */\n\nSTBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);\n/*  computes a scale factor to produce a font whose \"height\" is 'pixels' tall. */\n/*  Height is measured as the distance from the highest ascender to the lowest */\n/*  descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics */\n/*  and computing: */\n/*        scale = pixels / (ascent - descent) */\n/*  so if you prefer to measure height by the ascent only, use a similar calculation. */\n\nSTBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);\n/*  computes a scale factor to produce a font whose EM size is mapped to */\n/*  'pixels' tall. This is probably what traditional APIs compute, but */\n/*  I'm not positive. */\n\nSTBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);\n/*  ascent is the coordinate above the baseline the font extends; descent */\n/*  is the coordinate below the baseline the font extends (i.e. it is typically negative) */\n/*  lineGap is the spacing between one row's descent and the next row's ascent... */\n/*  so you should advance the vertical position by \"*ascent - *descent + *lineGap\" */\n/*    these are expressed in unscaled coordinates, so you must multiply by */\n/*    the scale factor for a given size */\n\nSTBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);\n/*  analogous to GetFontVMetrics, but returns the \"typographic\" values from the OS/2 */\n/*  table (specific to MS/Windows TTF files). */\n/*  */\n/*  Returns 1 on success (table present), 0 on failure. */\n\nSTBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);\n/*  the bounding box around all possible characters */\n\nSTBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);\n/*  leftSideBearing is the offset from the current horizontal position to the left edge of the character */\n/*  advanceWidth is the offset from the current horizontal position to the next horizontal position */\n/*    these are expressed in unscaled coordinates */\n\nSTBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);\n/*  an additional amount to add to the 'advance' value between ch1 and ch2 */\n\nSTBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);\n/*  Gets the bounding box of the visible part of the glyph, in unscaled coordinates */\n\nSTBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);\nSTBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);\nSTBTT_DEF int  stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);\n/*  as above, but takes one or more glyph indices for greater efficiency */\n\ntypedef struct stbtt_kerningentry\n{\n   int glyph1; /*  use stbtt_FindGlyphIndex */\n   int glyph2;\n   int advance;\n} stbtt_kerningentry;\n\nSTBTT_DEF int  stbtt_GetKerningTableLength(const stbtt_fontinfo *info);\nSTBTT_DEF int  stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length);\n/*  Retrieves a complete list of all of the kerning pairs provided by the font */\n/*  stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write. */\n/*  The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1) */\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  GLYPH SHAPES (you probably don't need these, but they have to go before */\n/*  the bitmaps for C declaration-order reasons) */\n/*  */\n\n#ifndef STBTT_vmove /*  you can predefine these to use different values (but why?) */\n   enum {\n      STBTT_vmove=1,\n      STBTT_vline,\n      STBTT_vcurve,\n      STBTT_vcubic\n   };\n#endif\n\n#ifndef stbtt_vertex /*  you can predefine this to use different values */\n                   /*  (we share this with other code at RAD) */\n   #define stbtt_vertex_type short /*  can't use stbtt_int16 because that's not visible in the header file */\n   typedef struct\n   {\n      stbtt_vertex_type x,y,cx,cy,cx1,cy1;\n      unsigned char type,padding;\n   } stbtt_vertex;\n#endif\n\nSTBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);\n/*  returns non-zero if nothing is drawn for this glyph */\n\nSTBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);\nSTBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);\n/*  returns # of vertices and fills *vertices with the pointer to them */\n/*    these are expressed in \"unscaled\" coordinates */\n/*  */\n/*  The shape is a series of contours. Each one starts with */\n/*  a STBTT_moveto, then consists of a series of mixed */\n/*  STBTT_lineto and STBTT_curveto segments. A lineto */\n/*  draws a line from previous endpoint to its x,y; a curveto */\n/*  draws a quadratic bezier from previous endpoint to */\n/*  its x,y, using cx,cy as the bezier control point. */\n\nSTBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);\n/*  frees the data allocated above */\n\nSTBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl);\nSTBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);\nSTBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);\n/*  fills svg with the character's SVG data. */\n/*  returns data size or 0 if SVG not found. */\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  BITMAP RENDERING */\n/*  */\n\nSTBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);\n/*  frees the bitmap allocated below */\n\nSTBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);\n/*  allocates a large-enough single-channel 8bpp bitmap and renders the */\n/*  specified character/glyph at the specified scale into it, with */\n/*  antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque). */\n/*  *width & *height are filled out with the width & height of the bitmap, */\n/*  which is stored left-to-right, top-to-bottom. */\n/*  */\n/*  xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap */\n\nSTBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);\n/*  the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel */\n/*  shift for the character */\n\nSTBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);\n/*  the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap */\n/*  in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap */\n/*  is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the */\n/*  width and height and positioning info for it first. */\n\nSTBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);\n/*  same as stbtt_MakeCodepointBitmap, but you can specify a subpixel */\n/*  shift for the character */\n\nSTBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);\n/*  same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering */\n/*  is performed (see stbtt_PackSetOversampling) */\n\nSTBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);\n/*  get the bbox of the bitmap centered around the glyph origin; so the */\n/*  bitmap width is ix1-ix0, height is iy1-iy0, and location to place */\n/*  the bitmap top left is (leftSideBearing*scale,iy0). */\n/*  (Note that the bitmap uses y-increases-down, but the shape uses */\n/*  y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.) */\n\nSTBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);\n/*  same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel */\n/*  shift for the character */\n\n/*  the following functions are equivalent to the above functions, but operate */\n/*  on glyph indices instead of Unicode codepoints (for efficiency) */\nSTBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);\nSTBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);\nSTBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);\nSTBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);\nSTBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);\nSTBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);\nSTBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);\n\n\n/*  @TODO: don't expose this structure */\ntypedef struct\n{\n   int w,h,stride;\n   unsigned char *pixels;\n} stbtt__bitmap;\n\n/*  rasterize a shape with quadratic beziers into a bitmap */\nSTBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result,        /*  1-channel bitmap to draw into */\n                               float flatness_in_pixels,     /*  allowable error of curve in pixels */\n                               stbtt_vertex *vertices,       /*  array of vertices defining shape */\n                               int num_verts,                /*  number of vertices in above array */\n                               float scale_x, float scale_y, /*  scale applied to input vertices */\n                               float shift_x, float shift_y, /*  translation applied to input vertices */\n                               int x_off, int y_off,         /*  another translation applied to input */\n                               int invert,                   /*  if non-zero, vertically flip shape */\n                               void *userdata);              /*  context for to STBTT_MALLOC */\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  Signed Distance Function (or Field) rendering */\n\nSTBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);\n/*  frees the SDF bitmap allocated below */\n\nSTBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);\nSTBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);\n/*  These functions compute a discretized SDF field for a single character, suitable for storing */\n/*  in a single-channel texture, sampling with bilinear filtering, and testing against */\n/*  larger than some threshold to produce scalable fonts. */\n/*         info              --  the font */\n/*         scale             --  controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap */\n/*         glyph/codepoint   --  the character to generate the SDF for */\n/*         padding           --  extra \"pixels\" around the character which are filled with the distance to the character (not 0), */\n/*                                  which allows effects like bit outlines */\n/*         onedge_value      --  value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character) */\n/*         pixel_dist_scale  --  what value the SDF should increase by when moving one SDF \"pixel\" away from the edge (on the 0..255 scale) */\n/*                                  if positive, > onedge_value is inside; if negative, < onedge_value is inside */\n/*         width,height      --  output height & width of the SDF bitmap (including padding) */\n/*         xoff,yoff         --  output origin of the character */\n/*         return value      --  a 2D array of bytes 0..255, width*height in size */\n/*  */\n/*  pixel_dist_scale & onedge_value are a scale & bias that allows you to make */\n/*  optimal use of the limited 0..255 for your application, trading off precision */\n/*  and special effects. SDF values outside the range 0..255 are clamped to 0..255. */\n/*  */\n/*  Example: */\n/*       scale = stbtt_ScaleForPixelHeight(22) */\n/*       padding = 5 */\n/*       onedge_value = 180 */\n/*       pixel_dist_scale = 180/5.0 = 36.0 */\n/*  */\n/*       This will create an SDF bitmap in which the character is about 22 pixels */\n/*       high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled */\n/*       shape, sample the SDF at each pixel and fill the pixel if the SDF value */\n/*       is greater than or equal to 180/255. (You'll actually want to antialias, */\n/*       which is beyond the scope of this example.) Additionally, you can compute */\n/*       offset outlines (e.g. to stroke the character border inside & outside, */\n/*       or only outside). For example, to fill outside the character up to 3 SDF */\n/*       pixels, you would compare against (180-36.0*3)/255 = 72/255. The above */\n/*       choice of variables maps a range from 5 pixels outside the shape to */\n/*       2 pixels inside the shape to 0..255; this is intended primarily for apply */\n/*       outside effects only (the interior range is needed to allow proper */\n/*       antialiasing of the font at *smaller* sizes) */\n/*  */\n/*  The function computes the SDF analytically at each SDF pixel, not by e.g. */\n/*  building a higher-res bitmap and approximating it. In theory the quality */\n/*  should be as high as possible for an SDF of this size & representation, but */\n/*  unclear if this is true in practice (perhaps building a higher-res bitmap */\n/*  and computing from that can allow drop-out prevention). */\n/*  */\n/*  The algorithm has not been optimized at all, so expect it to be slow */\n/*  if computing lots of characters or very large sizes. */\n\n\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  Finding the right font... */\n/*  */\n/*  You should really just solve this offline, keep your own tables */\n/*  of what font is what, and don't try to get it out of the .ttf file. */\n/*  That's because getting it out of the .ttf file is really hard, because */\n/*  the names in the file can appear in many possible encodings, in many */\n/*  possible languages, and e.g. if you need a case-insensitive comparison, */\n/*  the details of that depend on the encoding & language in a complex way */\n/*  (actually underspecified in truetype, but also gigantic). */\n/*  */\n/*  But you can use the provided functions in two possible ways: */\n/*      stbtt_FindMatchingFont() will use *case-sensitive* comparisons on */\n/*              unicode-encoded names to try to find the font you want; */\n/*              you can run this before calling stbtt_InitFont() */\n/*  */\n/*      stbtt_GetFontNameString() lets you get any of the various strings */\n/*              from the file yourself and do your own comparisons on them. */\n/*              You have to have called stbtt_InitFont() first. */\n\n\nSTBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);\n/*  returns the offset (not index) of the font that matches, or -1 if none */\n/*    if you use STBTT_MACSTYLE_DONTCARE, use a font name like \"Arial Bold\". */\n/*    if you use any other flag, use a font name like \"Arial\"; this checks */\n/*      the 'macStyle' header field; i don't know if fonts set this consistently */\n#define STBTT_MACSTYLE_DONTCARE     0\n#define STBTT_MACSTYLE_BOLD         1\n#define STBTT_MACSTYLE_ITALIC       2\n#define STBTT_MACSTYLE_UNDERSCORE   4\n#define STBTT_MACSTYLE_NONE         8   /*  <= not same as 0, this makes us check the bitfield is 0 */\n\nSTBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);\n/*  returns 1/0 whether the first string interpreted as utf8 is identical to */\n/*  the second string interpreted as big-endian utf16... useful for strings from next func */\n\nSTBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);\n/*  returns the string (which may be big-endian double byte, e.g. for unicode) */\n/*  and puts the length in bytes in *length. */\n/*  */\n/*  some of the values for the IDs are below; for more see the truetype spec: */\n/*      http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html */\n/*      http://www.microsoft.com/typography/otspec/name.htm */\n\nenum { /*  platformID */\n   STBTT_PLATFORM_ID_UNICODE   =0,\n   STBTT_PLATFORM_ID_MAC       =1,\n   STBTT_PLATFORM_ID_ISO       =2,\n   STBTT_PLATFORM_ID_MICROSOFT =3\n};\n\nenum { /*  encodingID for STBTT_PLATFORM_ID_UNICODE */\n   STBTT_UNICODE_EID_UNICODE_1_0    =0,\n   STBTT_UNICODE_EID_UNICODE_1_1    =1,\n   STBTT_UNICODE_EID_ISO_10646      =2,\n   STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,\n   STBTT_UNICODE_EID_UNICODE_2_0_FULL=4\n};\n\nenum { /*  encodingID for STBTT_PLATFORM_ID_MICROSOFT */\n   STBTT_MS_EID_SYMBOL        =0,\n   STBTT_MS_EID_UNICODE_BMP   =1,\n   STBTT_MS_EID_SHIFTJIS      =2,\n   STBTT_MS_EID_UNICODE_FULL  =10\n};\n\nenum { /*  encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes */\n   STBTT_MAC_EID_ROMAN        =0,   STBTT_MAC_EID_ARABIC       =4,\n   STBTT_MAC_EID_JAPANESE     =1,   STBTT_MAC_EID_HEBREW       =5,\n   STBTT_MAC_EID_CHINESE_TRAD =2,   STBTT_MAC_EID_GREEK        =6,\n   STBTT_MAC_EID_KOREAN       =3,   STBTT_MAC_EID_RUSSIAN      =7\n};\n\nenum { /*  languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID... */\n       /*  problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs */\n   STBTT_MS_LANG_ENGLISH     =0x0409,   STBTT_MS_LANG_ITALIAN     =0x0410,\n   STBTT_MS_LANG_CHINESE     =0x0804,   STBTT_MS_LANG_JAPANESE    =0x0411,\n   STBTT_MS_LANG_DUTCH       =0x0413,   STBTT_MS_LANG_KOREAN      =0x0412,\n   STBTT_MS_LANG_FRENCH      =0x040c,   STBTT_MS_LANG_RUSSIAN     =0x0419,\n   STBTT_MS_LANG_GERMAN      =0x0407,   STBTT_MS_LANG_SPANISH     =0x0409,\n   STBTT_MS_LANG_HEBREW      =0x040d,   STBTT_MS_LANG_SWEDISH     =0x041D\n};\n\nenum { /*  languageID for STBTT_PLATFORM_ID_MAC */\n   STBTT_MAC_LANG_ENGLISH      =0 ,   STBTT_MAC_LANG_JAPANESE     =11,\n   STBTT_MAC_LANG_ARABIC       =12,   STBTT_MAC_LANG_KOREAN       =23,\n   STBTT_MAC_LANG_DUTCH        =4 ,   STBTT_MAC_LANG_RUSSIAN      =32,\n   STBTT_MAC_LANG_FRENCH       =1 ,   STBTT_MAC_LANG_SPANISH      =6 ,\n   STBTT_MAC_LANG_GERMAN       =2 ,   STBTT_MAC_LANG_SWEDISH      =5 ,\n   STBTT_MAC_LANG_HEBREW       =10,   STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,\n   STBTT_MAC_LANG_ITALIAN      =3 ,   STBTT_MAC_LANG_CHINESE_TRAD =19\n};\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /*  __STB_INCLUDE_STB_TRUETYPE_H__ */\n\n/* ///////////////////////////////////////////////////////////////////////////// */\n/* ///////////////////////////////////////////////////////////////////////////// */\n/* // */\n/* //   IMPLEMENTATION */\n/* // */\n/* // */\n\n#ifdef STB_TRUETYPE_IMPLEMENTATION\n\n#ifndef STBTT_MAX_OVERSAMPLE\n#define STBTT_MAX_OVERSAMPLE   8\n#endif\n\n#if STBTT_MAX_OVERSAMPLE > 255\n#error \"STBTT_MAX_OVERSAMPLE cannot be > 255\"\n#endif\n\ntypedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];\n\n#ifndef STBTT_RASTERIZER_VERSION\n#define STBTT_RASTERIZER_VERSION 2\n#endif\n\n#ifdef _MSC_VER\n#define STBTT__NOTUSED(v)  (void)(v)\n#else\n#define STBTT__NOTUSED(v)  (void)sizeof(v)\n#endif\n\n/* //////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  stbtt__buf helpers to parse data from file */\n/*  */\n\nstatic stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)\n{\n   if (b->cursor >= b->size)\n      return 0;\n   return b->data[b->cursor++];\n}\n\nstatic stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)\n{\n   if (b->cursor >= b->size)\n      return 0;\n   return b->data[b->cursor];\n}\n\nstatic void stbtt__buf_seek(stbtt__buf *b, int o)\n{\n   STBTT_assert(!(o > b->size || o < 0));\n   b->cursor = (o > b->size || o < 0) ? b->size : o;\n}\n\nstatic void stbtt__buf_skip(stbtt__buf *b, int o)\n{\n   stbtt__buf_seek(b, b->cursor + o);\n}\n\nstatic stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)\n{\n   stbtt_uint32 v = 0;\n   int i;\n   STBTT_assert(n >= 1 && n <= 4);\n   for (i = 0; i < n; i++)\n      v = (v << 8) | stbtt__buf_get8(b);\n   return v;\n}\n\nstatic stbtt__buf stbtt__new_buf(const void *p, size_t size)\n{\n   stbtt__buf r;\n   STBTT_assert(size < 0x40000000);\n   r.data = (stbtt_uint8*) p;\n   r.size = (int) size;\n   r.cursor = 0;\n   return r;\n}\n\n#define stbtt__buf_get16(b)  stbtt__buf_get((b), 2)\n#define stbtt__buf_get32(b)  stbtt__buf_get((b), 4)\n\nstatic stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s)\n{\n   stbtt__buf r = stbtt__new_buf(NULL, 0);\n   if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r;\n   r.data = b->data + o;\n   r.size = s;\n   return r;\n}\n\nstatic stbtt__buf stbtt__cff_get_index(stbtt__buf *b)\n{\n   int count, start, offsize;\n   start = b->cursor;\n   count = stbtt__buf_get16(b);\n   if (count) {\n      offsize = stbtt__buf_get8(b);\n      STBTT_assert(offsize >= 1 && offsize <= 4);\n      stbtt__buf_skip(b, offsize * count);\n      stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);\n   }\n   return stbtt__buf_range(b, start, b->cursor - start);\n}\n\nstatic stbtt_uint32 stbtt__cff_int(stbtt__buf *b)\n{\n   int b0 = stbtt__buf_get8(b);\n   if (b0 >= 32 && b0 <= 246)       return b0 - 139;\n   else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;\n   else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;\n   else if (b0 == 28)               return stbtt__buf_get16(b);\n   else if (b0 == 29)               return stbtt__buf_get32(b);\n   STBTT_assert(0);\n   return 0;\n}\n\nstatic void stbtt__cff_skip_operand(stbtt__buf *b) {\n   int v, b0 = stbtt__buf_peek8(b);\n   STBTT_assert(b0 >= 28);\n   if (b0 == 30) {\n      stbtt__buf_skip(b, 1);\n      while (b->cursor < b->size) {\n         v = stbtt__buf_get8(b);\n         if ((v & 0xF) == 0xF || (v >> 4) == 0xF)\n            break;\n      }\n   } else {\n      stbtt__cff_int(b);\n   }\n}\n\nstatic stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)\n{\n   stbtt__buf_seek(b, 0);\n   while (b->cursor < b->size) {\n      int start = b->cursor, end, op;\n      while (stbtt__buf_peek8(b) >= 28)\n         stbtt__cff_skip_operand(b);\n      end = b->cursor;\n      op = stbtt__buf_get8(b);\n      if (op == 12)  op = stbtt__buf_get8(b) | 0x100;\n      if (op == key) return stbtt__buf_range(b, start, end-start);\n   }\n   return stbtt__buf_range(b, 0, 0);\n}\n\nstatic void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out)\n{\n   int i;\n   stbtt__buf operands = stbtt__dict_get(b, key);\n   for (i = 0; i < outcount && operands.cursor < operands.size; i++)\n      out[i] = stbtt__cff_int(&operands);\n}\n\nstatic int stbtt__cff_index_count(stbtt__buf *b)\n{\n   stbtt__buf_seek(b, 0);\n   return stbtt__buf_get16(b);\n}\n\nstatic stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)\n{\n   int count, offsize, start, end;\n   stbtt__buf_seek(&b, 0);\n   count = stbtt__buf_get16(&b);\n   offsize = stbtt__buf_get8(&b);\n   STBTT_assert(i >= 0 && i < count);\n   STBTT_assert(offsize >= 1 && offsize <= 4);\n   stbtt__buf_skip(&b, i*offsize);\n   start = stbtt__buf_get(&b, offsize);\n   end = stbtt__buf_get(&b, offsize);\n   return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);\n}\n\n/* //////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  accessors to parse data from file */\n/*  */\n\n/*  on platforms that don't allow misaligned reads, if we want to allow */\n/*  truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE */\n\n#define ttBYTE(p)     (* (stbtt_uint8 *) (p))\n#define ttCHAR(p)     (* (stbtt_int8 *) (p))\n#define ttFixed(p)    ttLONG(p)\n\nstatic stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }\nstatic stbtt_int16 ttSHORT(stbtt_uint8 *p)   { return p[0]*256 + p[1]; }\nstatic stbtt_uint32 ttULONG(stbtt_uint8 *p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }\nstatic stbtt_int32 ttLONG(stbtt_uint8 *p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }\n\n#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))\n#define stbtt_tag(p,str)           stbtt_tag4(p,str[0],str[1],str[2],str[3])\n\nstatic int stbtt__isfont(stbtt_uint8 *font)\n{\n   /*  check the version number */\n   if (stbtt_tag4(font, '1',0,0,0))  return 1; /*  TrueType 1 */\n   if (stbtt_tag(font, \"typ1\"))   return 1; /*  TrueType with type 1 font -- we don't support this! */\n   if (stbtt_tag(font, \"OTTO\"))   return 1; /*  OpenType with CFF */\n   if (stbtt_tag4(font, 0,1,0,0)) return 1; /*  OpenType 1.0 */\n   if (stbtt_tag(font, \"true\"))   return 1; /*  Apple specification for TrueType fonts */\n   return 0;\n}\n\n/*  @OPTIMIZE: binary search */\nstatic stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)\n{\n   stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);\n   stbtt_uint32 tabledir = fontstart + 12;\n   stbtt_int32 i;\n   for (i=0; i < num_tables; ++i) {\n      stbtt_uint32 loc = tabledir + 16*i;\n      if (stbtt_tag(data+loc+0, tag))\n         return ttULONG(data+loc+8);\n   }\n   return 0;\n}\n\nstatic int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index)\n{\n   /*  if it's just a font, there's only one valid index */\n   if (stbtt__isfont(font_collection))\n      return index == 0 ? 0 : -1;\n\n   /*  check if it's a TTC */\n   if (stbtt_tag(font_collection, \"ttcf\")) {\n      /*  version 1? */\n      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {\n         stbtt_int32 n = ttLONG(font_collection+8);\n         if (index >= n)\n            return -1;\n         return ttULONG(font_collection+12+index*4);\n      }\n   }\n   return -1;\n}\n\nstatic int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection)\n{\n   /*  if it's just a font, there's only one valid font */\n   if (stbtt__isfont(font_collection))\n      return 1;\n\n   /*  check if it's a TTC */\n   if (stbtt_tag(font_collection, \"ttcf\")) {\n      /*  version 1? */\n      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {\n         return ttLONG(font_collection+8);\n      }\n   }\n   return 0;\n}\n\nstatic stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)\n{\n   stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 };\n   stbtt__buf pdict;\n   stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);\n   if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0);\n   pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);\n   stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);\n   if (!subrsoff) return stbtt__new_buf(NULL, 0);\n   stbtt__buf_seek(&cff, private_loc[1]+subrsoff);\n   return stbtt__cff_get_index(&cff);\n}\n\n/*  since most people won't use this, find this table the first time it's needed */\nstatic int stbtt__get_svg(stbtt_fontinfo *info)\n{\n   stbtt_uint32 t;\n   if (info->svg < 0) {\n      t = stbtt__find_table(info->data, info->fontstart, \"SVG \");\n      if (t) {\n         stbtt_uint32 offset = ttULONG(info->data + t + 2);\n         info->svg = t + offset;\n      } else {\n         info->svg = 0;\n      }\n   }\n   return info->svg;\n}\n\nstatic int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)\n{\n   stbtt_uint32 cmap, t;\n   stbtt_int32 i,numTables;\n\n   info->data = data;\n   info->fontstart = fontstart;\n   info->cff = stbtt__new_buf(NULL, 0);\n\n   cmap = stbtt__find_table(data, fontstart, \"cmap\");       /*  required */\n   info->loca = stbtt__find_table(data, fontstart, \"loca\"); /*  required */\n   info->head = stbtt__find_table(data, fontstart, \"head\"); /*  required */\n   info->glyf = stbtt__find_table(data, fontstart, \"glyf\"); /*  required */\n   info->hhea = stbtt__find_table(data, fontstart, \"hhea\"); /*  required */\n   info->hmtx = stbtt__find_table(data, fontstart, \"hmtx\"); /*  required */\n   info->kern = stbtt__find_table(data, fontstart, \"kern\"); /*  not required */\n   info->gpos = stbtt__find_table(data, fontstart, \"GPOS\"); /*  not required */\n\n   if (!cmap || !info->head || !info->hhea || !info->hmtx)\n      return 0;\n   if (info->glyf) {\n      /*  required for truetype */\n      if (!info->loca) return 0;\n   } else {\n      /*  initialization for CFF / Type2 fonts (OTF) */\n      stbtt__buf b, topdict, topdictidx;\n      stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;\n      stbtt_uint32 cff;\n\n      cff = stbtt__find_table(data, fontstart, \"CFF \");\n      if (!cff) return 0;\n\n      info->fontdicts = stbtt__new_buf(NULL, 0);\n      info->fdselect = stbtt__new_buf(NULL, 0);\n\n      /*  @TODO this should use size from table (not 512MB) */\n      info->cff = stbtt__new_buf(data+cff, 512*1024*1024);\n      b = info->cff;\n\n      /*  read the header */\n      stbtt__buf_skip(&b, 2);\n      stbtt__buf_seek(&b, stbtt__buf_get8(&b)); /*  hdrsize */\n\n      /*  @TODO the name INDEX could list multiple fonts, */\n      /*  but we just use the first one. */\n      stbtt__cff_get_index(&b);  /*  name INDEX */\n      topdictidx = stbtt__cff_get_index(&b);\n      topdict = stbtt__cff_index_get(topdictidx, 0);\n      stbtt__cff_get_index(&b);  /*  string INDEX */\n      info->gsubrs = stbtt__cff_get_index(&b);\n\n      stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);\n      stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);\n      stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);\n      stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);\n      info->subrs = stbtt__get_subrs(b, topdict);\n\n      /*  we only support Type 2 charstrings */\n      if (cstype != 2) return 0;\n      if (charstrings == 0) return 0;\n\n      if (fdarrayoff) {\n         /*  looks like a CID font */\n         if (!fdselectoff) return 0;\n         stbtt__buf_seek(&b, fdarrayoff);\n         info->fontdicts = stbtt__cff_get_index(&b);\n         info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);\n      }\n\n      stbtt__buf_seek(&b, charstrings);\n      info->charstrings = stbtt__cff_get_index(&b);\n   }\n\n   t = stbtt__find_table(data, fontstart, \"maxp\");\n   if (t)\n      info->numGlyphs = ttUSHORT(data+t+4);\n   else\n      info->numGlyphs = 0xffff;\n\n   info->svg = -1;\n\n   /*  find a cmap encoding table we understand *now* to avoid searching */\n   /*  later. (todo: could make this installable) */\n   /*  the same regardless of glyph. */\n   numTables = ttUSHORT(data + cmap + 2);\n   info->index_map = 0;\n   for (i=0; i < numTables; ++i) {\n      stbtt_uint32 encoding_record = cmap + 4 + 8 * i;\n      /*  find an encoding we understand: */\n      switch(ttUSHORT(data+encoding_record)) {\n         case STBTT_PLATFORM_ID_MICROSOFT:\n            switch (ttUSHORT(data+encoding_record+2)) {\n               case STBTT_MS_EID_UNICODE_BMP:\n               case STBTT_MS_EID_UNICODE_FULL:\n                  /*  MS/Unicode */\n                  info->index_map = cmap + ttULONG(data+encoding_record+4);\n                  break;\n            }\n            break;\n        case STBTT_PLATFORM_ID_UNICODE:\n            /*  Mac/iOS has these */\n            /*  all the encodingIDs are unicode, so we don't bother to check it */\n            info->index_map = cmap + ttULONG(data+encoding_record+4);\n            break;\n      }\n   }\n   if (info->index_map == 0)\n      return 0;\n\n   info->indexToLocFormat = ttUSHORT(data+info->head + 50);\n   return 1;\n}\n\nSTBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)\n{\n   stbtt_uint8 *data = info->data;\n   stbtt_uint32 index_map = info->index_map;\n\n   stbtt_uint16 format = ttUSHORT(data + index_map + 0);\n   if (format == 0) { /*  apple byte encoding */\n      stbtt_int32 bytes = ttUSHORT(data + index_map + 2);\n      if (unicode_codepoint < bytes-6)\n         return ttBYTE(data + index_map + 6 + unicode_codepoint);\n      return 0;\n   } else if (format == 6) {\n      stbtt_uint32 first = ttUSHORT(data + index_map + 6);\n      stbtt_uint32 count = ttUSHORT(data + index_map + 8);\n      if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)\n         return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);\n      return 0;\n   } else if (format == 2) {\n      STBTT_assert(0); /*  @TODO: high-byte mapping for japanese/chinese/korean */\n      return 0;\n   } else if (format == 4) { /*  standard mapping for windows fonts: binary search collection of ranges */\n      stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;\n      stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;\n      stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);\n      stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;\n\n      /*  do a binary search of the segments */\n      stbtt_uint32 endCount = index_map + 14;\n      stbtt_uint32 search = endCount;\n\n      if (unicode_codepoint > 0xffff)\n         return 0;\n\n      /*  they lie from endCount .. endCount + segCount */\n      /*  but searchRange is the nearest power of two, so... */\n      if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))\n         search += rangeShift*2;\n\n      /*  now decrement to bias correctly to find smallest */\n      search -= 2;\n      while (entrySelector) {\n         stbtt_uint16 end;\n         searchRange >>= 1;\n         end = ttUSHORT(data + search + searchRange*2);\n         if (unicode_codepoint > end)\n            search += searchRange*2;\n         --entrySelector;\n      }\n      search += 2;\n\n      {\n         stbtt_uint16 offset, start, last;\n         stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);\n\n         start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);\n         last = ttUSHORT(data + endCount + 2*item);\n         if (unicode_codepoint < start || unicode_codepoint > last)\n            return 0;\n\n         offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);\n         if (offset == 0)\n            return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));\n\n         return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);\n      }\n   } else if (format == 12 || format == 13) {\n      stbtt_uint32 ngroups = ttULONG(data+index_map+12);\n      stbtt_int32 low,high;\n      low = 0; high = (stbtt_int32)ngroups;\n      /*  Binary search the right group. */\n      while (low < high) {\n         stbtt_int32 mid = low + ((high-low) >> 1); /*  rounds down, so low <= mid < high */\n         stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);\n         stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);\n         if ((stbtt_uint32) unicode_codepoint < start_char)\n            high = mid;\n         else if ((stbtt_uint32) unicode_codepoint > end_char)\n            low = mid+1;\n         else {\n            stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);\n            if (format == 12)\n               return start_glyph + unicode_codepoint-start_char;\n            else /*  format == 13 */\n               return start_glyph;\n         }\n      }\n      return 0; /*  not found */\n   }\n   /*  @TODO */\n   STBTT_assert(0);\n   return 0;\n}\n\nSTBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)\n{\n   return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);\n}\n\nstatic void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)\n{\n   v->type = type;\n   v->x = (stbtt_int16) x;\n   v->y = (stbtt_int16) y;\n   v->cx = (stbtt_int16) cx;\n   v->cy = (stbtt_int16) cy;\n}\n\nstatic int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)\n{\n   int g1,g2;\n\n   STBTT_assert(!info->cff.size);\n\n   if (glyph_index >= info->numGlyphs) return -1; /*  glyph index out of range */\n   if (info->indexToLocFormat >= 2)    return -1; /*  unknown index->glyph map format */\n\n   if (info->indexToLocFormat == 0) {\n      g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;\n      g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;\n   } else {\n      g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);\n      g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);\n   }\n\n   return g1==g2 ? -1 : g1; /*  if length is 0, return -1 */\n}\n\nstatic int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);\n\nSTBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)\n{\n   if (info->cff.size) {\n      stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);\n   } else {\n      int g = stbtt__GetGlyfOffset(info, glyph_index);\n      if (g < 0) return 0;\n\n      if (x0) *x0 = ttSHORT(info->data + g + 2);\n      if (y0) *y0 = ttSHORT(info->data + g + 4);\n      if (x1) *x1 = ttSHORT(info->data + g + 6);\n      if (y1) *y1 = ttSHORT(info->data + g + 8);\n   }\n   return 1;\n}\n\nSTBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)\n{\n   return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);\n}\n\nSTBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)\n{\n   stbtt_int16 numberOfContours;\n   int g;\n   if (info->cff.size)\n      return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;\n   g = stbtt__GetGlyfOffset(info, glyph_index);\n   if (g < 0) return 1;\n   numberOfContours = ttSHORT(info->data + g);\n   return numberOfContours == 0;\n}\n\nstatic int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,\n    stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)\n{\n   if (start_off) {\n      if (was_off)\n         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);\n      stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);\n   } else {\n      if (was_off)\n         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);\n      else\n         stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);\n   }\n   return num_vertices;\n}\n\nstatic int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)\n{\n   stbtt_int16 numberOfContours;\n   stbtt_uint8 *endPtsOfContours;\n   stbtt_uint8 *data = info->data;\n   stbtt_vertex *vertices=0;\n   int num_vertices=0;\n   int g = stbtt__GetGlyfOffset(info, glyph_index);\n\n   *pvertices = NULL;\n\n   if (g < 0) return 0;\n\n   numberOfContours = ttSHORT(data + g);\n\n   if (numberOfContours > 0) {\n      stbtt_uint8 flags=0,flagcount;\n      stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;\n      stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;\n      stbtt_uint8 *points;\n      endPtsOfContours = (data + g + 10);\n      ins = ttUSHORT(data + g + 10 + numberOfContours * 2);\n      points = data + g + 10 + numberOfContours * 2 + 2 + ins;\n\n      n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);\n\n      m = n + 2*numberOfContours;  /*  a loose bound on how many vertices we might need */\n      vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);\n      if (vertices == 0)\n         return 0;\n\n      next_move = 0;\n      flagcount=0;\n\n      /*  in first pass, we load uninterpreted data into the allocated array */\n      /*  above, shifted to the end of the array so we won't overwrite it when */\n      /*  we create our final data starting from the front */\n\n      off = m - n; /*  starting offset for uninterpreted data, regardless of how m ends up being calculated */\n\n      /*  first load flags */\n\n      for (i=0; i < n; ++i) {\n         if (flagcount == 0) {\n            flags = *points++;\n            if (flags & 8)\n               flagcount = *points++;\n         } else\n            --flagcount;\n         vertices[off+i].type = flags;\n      }\n\n      /*  now load x coordinates */\n      x=0;\n      for (i=0; i < n; ++i) {\n         flags = vertices[off+i].type;\n         if (flags & 2) {\n            stbtt_int16 dx = *points++;\n            x += (flags & 16) ? dx : -dx; /*  ??? */\n         } else {\n            if (!(flags & 16)) {\n               x = x + (stbtt_int16) (points[0]*256 + points[1]);\n               points += 2;\n            }\n         }\n         vertices[off+i].x = (stbtt_int16) x;\n      }\n\n      /*  now load y coordinates */\n      y=0;\n      for (i=0; i < n; ++i) {\n         flags = vertices[off+i].type;\n         if (flags & 4) {\n            stbtt_int16 dy = *points++;\n            y += (flags & 32) ? dy : -dy; /*  ??? */\n         } else {\n            if (!(flags & 32)) {\n               y = y + (stbtt_int16) (points[0]*256 + points[1]);\n               points += 2;\n            }\n         }\n         vertices[off+i].y = (stbtt_int16) y;\n      }\n\n      /*  now convert them to our format */\n      num_vertices=0;\n      sx = sy = cx = cy = scx = scy = 0;\n      for (i=0; i < n; ++i) {\n         flags = vertices[off+i].type;\n         x     = (stbtt_int16) vertices[off+i].x;\n         y     = (stbtt_int16) vertices[off+i].y;\n\n         if (next_move == i) {\n            if (i != 0)\n               num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);\n\n            /*  now start the new one */\n            start_off = !(flags & 1);\n            if (start_off) {\n               /*  if we start off with an off-curve point, then when we need to find a point on the curve */\n               /*  where we can start, and we need to save some state for when we wraparound. */\n               scx = x;\n               scy = y;\n               if (!(vertices[off+i+1].type & 1)) {\n                  /*  next point is also a curve point, so interpolate an on-point curve */\n                  sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;\n                  sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;\n               } else {\n                  /*  otherwise just use the next point as our start point */\n                  sx = (stbtt_int32) vertices[off+i+1].x;\n                  sy = (stbtt_int32) vertices[off+i+1].y;\n                  ++i; /*  we're using point i+1 as the starting point, so skip it */\n               }\n            } else {\n               sx = x;\n               sy = y;\n            }\n            stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);\n            was_off = 0;\n            next_move = 1 + ttUSHORT(endPtsOfContours+j*2);\n            ++j;\n         } else {\n            if (!(flags & 1)) { /*  if it's a curve */\n               if (was_off) /*  two off-curve control points in a row means interpolate an on-curve midpoint */\n                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);\n               cx = x;\n               cy = y;\n               was_off = 1;\n            } else {\n               if (was_off)\n                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);\n               else\n                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);\n               was_off = 0;\n            }\n         }\n      }\n      num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);\n   } else if (numberOfContours < 0) {\n      /*  Compound shapes. */\n      int more = 1;\n      stbtt_uint8 *comp = data + g + 10;\n      num_vertices = 0;\n      vertices = 0;\n      while (more) {\n         stbtt_uint16 flags, gidx;\n         int comp_num_verts = 0, i;\n         stbtt_vertex *comp_verts = 0, *tmp = 0;\n         float mtx[6] = {1,0,0,1,0,0}, m, n;\n\n         flags = ttSHORT(comp); comp+=2;\n         gidx = ttSHORT(comp); comp+=2;\n\n         if (flags & 2) { /*  XY values */\n            if (flags & 1) { /*  shorts */\n               mtx[4] = ttSHORT(comp); comp+=2;\n               mtx[5] = ttSHORT(comp); comp+=2;\n            } else {\n               mtx[4] = ttCHAR(comp); comp+=1;\n               mtx[5] = ttCHAR(comp); comp+=1;\n            }\n         }\n         else {\n            /*  @TODO handle matching point */\n            STBTT_assert(0);\n         }\n         if (flags & (1<<3)) { /*  WE_HAVE_A_SCALE */\n            mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[1] = mtx[2] = 0;\n         } else if (flags & (1<<6)) { /*  WE_HAVE_AN_X_AND_YSCALE */\n            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[1] = mtx[2] = 0;\n            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;\n         } else if (flags & (1<<7)) { /*  WE_HAVE_A_TWO_BY_TWO */\n            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;\n         }\n\n         /*  Find transformation scales. */\n         m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);\n         n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);\n\n         /*  Get indexed glyph. */\n         comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);\n         if (comp_num_verts > 0) {\n            /*  Transform vertices. */\n            for (i = 0; i < comp_num_verts; ++i) {\n               stbtt_vertex* v = &comp_verts[i];\n               stbtt_vertex_type x,y;\n               x=v->x; y=v->y;\n               v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));\n               v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));\n               x=v->cx; y=v->cy;\n               v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));\n               v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));\n            }\n            /*  Append vertices. */\n            tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);\n            if (!tmp) {\n               if (vertices) STBTT_free(vertices, info->userdata);\n               if (comp_verts) STBTT_free(comp_verts, info->userdata);\n               return 0;\n            }\n            if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));\n            STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));\n            if (vertices) STBTT_free(vertices, info->userdata);\n            vertices = tmp;\n            STBTT_free(comp_verts, info->userdata);\n            num_vertices += comp_num_verts;\n         }\n         /*  More components ? */\n         more = flags & (1<<5);\n      }\n   } else {\n      /*  numberOfCounters == 0, do nothing */\n   }\n\n   *pvertices = vertices;\n   return num_vertices;\n}\n\ntypedef struct\n{\n   int bounds;\n   int started;\n   float first_x, first_y;\n   float x, y;\n   stbtt_int32 min_x, max_x, min_y, max_y;\n\n   stbtt_vertex *pvertices;\n   int num_vertices;\n} stbtt__csctx;\n\n#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}\n\nstatic void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)\n{\n   if (x > c->max_x || !c->started) c->max_x = x;\n   if (y > c->max_y || !c->started) c->max_y = y;\n   if (x < c->min_x || !c->started) c->min_x = x;\n   if (y < c->min_y || !c->started) c->min_y = y;\n   c->started = 1;\n}\n\nstatic void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1)\n{\n   if (c->bounds) {\n      stbtt__track_vertex(c, x, y);\n      if (type == STBTT_vcubic) {\n         stbtt__track_vertex(c, cx, cy);\n         stbtt__track_vertex(c, cx1, cy1);\n      }\n   } else {\n      stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);\n      c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;\n      c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;\n   }\n   c->num_vertices++;\n}\n\nstatic void stbtt__csctx_close_shape(stbtt__csctx *ctx)\n{\n   if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)\n      stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);\n}\n\nstatic void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)\n{\n   stbtt__csctx_close_shape(ctx);\n   ctx->first_x = ctx->x = ctx->x + dx;\n   ctx->first_y = ctx->y = ctx->y + dy;\n   stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);\n}\n\nstatic void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)\n{\n   ctx->x += dx;\n   ctx->y += dy;\n   stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);\n}\n\nstatic void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)\n{\n   float cx1 = ctx->x + dx1;\n   float cy1 = ctx->y + dy1;\n   float cx2 = cx1 + dx2;\n   float cy2 = cy1 + dy2;\n   ctx->x = cx2 + dx3;\n   ctx->y = cy2 + dy3;\n   stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);\n}\n\nstatic stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)\n{\n   int count = stbtt__cff_index_count(&idx);\n   int bias = 107;\n   if (count >= 33900)\n      bias = 32768;\n   else if (count >= 1240)\n      bias = 1131;\n   n += bias;\n   if (n < 0 || n >= count)\n      return stbtt__new_buf(NULL, 0);\n   return stbtt__cff_index_get(idx, n);\n}\n\nstatic stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index)\n{\n   stbtt__buf fdselect = info->fdselect;\n   int nranges, start, end, v, fmt, fdselector = -1, i;\n\n   stbtt__buf_seek(&fdselect, 0);\n   fmt = stbtt__buf_get8(&fdselect);\n   if (fmt == 0) {\n      /*  untested */\n      stbtt__buf_skip(&fdselect, glyph_index);\n      fdselector = stbtt__buf_get8(&fdselect);\n   } else if (fmt == 3) {\n      nranges = stbtt__buf_get16(&fdselect);\n      start = stbtt__buf_get16(&fdselect);\n      for (i = 0; i < nranges; i++) {\n         v = stbtt__buf_get8(&fdselect);\n         end = stbtt__buf_get16(&fdselect);\n         if (glyph_index >= start && glyph_index < end) {\n            fdselector = v;\n            break;\n         }\n         start = end;\n      }\n   }\n   if (fdselector == -1) stbtt__new_buf(NULL, 0);\n   return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));\n}\n\nstatic int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)\n{\n   int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;\n   int has_subrs = 0, clear_stack;\n   float s[48];\n   stbtt__buf subr_stack[10], subrs = info->subrs, b;\n   float f;\n\n#define STBTT__CSERR(s) (0)\n\n   /*  this currently ignores the initial width value, which isn't needed if we have hmtx */\n   b = stbtt__cff_index_get(info->charstrings, glyph_index);\n   while (b.cursor < b.size) {\n      i = 0;\n      clear_stack = 1;\n      b0 = stbtt__buf_get8(&b);\n      switch (b0) {\n      /*  @TODO implement hinting */\n      case 0x13: /*  hintmask */\n      case 0x14: /*  cntrmask */\n         if (in_header)\n            maskbits += (sp / 2); /*  implicit \"vstem\" */\n         in_header = 0;\n         stbtt__buf_skip(&b, (maskbits + 7) / 8);\n         break;\n\n      case 0x01: /*  hstem */\n      case 0x03: /*  vstem */\n      case 0x12: /*  hstemhm */\n      case 0x17: /*  vstemhm */\n         maskbits += (sp / 2);\n         break;\n\n      case 0x15: /*  rmoveto */\n         in_header = 0;\n         if (sp < 2) return STBTT__CSERR(\"rmoveto stack\");\n         stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);\n         break;\n      case 0x04: /*  vmoveto */\n         in_header = 0;\n         if (sp < 1) return STBTT__CSERR(\"vmoveto stack\");\n         stbtt__csctx_rmove_to(c, 0, s[sp-1]);\n         break;\n      case 0x16: /*  hmoveto */\n         in_header = 0;\n         if (sp < 1) return STBTT__CSERR(\"hmoveto stack\");\n         stbtt__csctx_rmove_to(c, s[sp-1], 0);\n         break;\n\n      case 0x05: /*  rlineto */\n         if (sp < 2) return STBTT__CSERR(\"rlineto stack\");\n         for (; i + 1 < sp; i += 2)\n            stbtt__csctx_rline_to(c, s[i], s[i+1]);\n         break;\n\n      /*  hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical */\n      /*  starting from a different place. */\n\n      case 0x07: /*  vlineto */\n         if (sp < 1) return STBTT__CSERR(\"vlineto stack\");\n         goto vlineto;\n      case 0x06: /*  hlineto */\n         if (sp < 1) return STBTT__CSERR(\"hlineto stack\");\n         for (;;) {\n            if (i >= sp) break;\n            stbtt__csctx_rline_to(c, s[i], 0);\n            i++;\n      vlineto:\n            if (i >= sp) break;\n            stbtt__csctx_rline_to(c, 0, s[i]);\n            i++;\n         }\n         break;\n\n      case 0x1F: /*  hvcurveto */\n         if (sp < 4) return STBTT__CSERR(\"hvcurveto stack\");\n         goto hvcurveto;\n      case 0x1E: /*  vhcurveto */\n         if (sp < 4) return STBTT__CSERR(\"vhcurveto stack\");\n         for (;;) {\n            if (i + 3 >= sp) break;\n            stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);\n            i += 4;\n      hvcurveto:\n            if (i + 3 >= sp) break;\n            stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);\n            i += 4;\n         }\n         break;\n\n      case 0x08: /*  rrcurveto */\n         if (sp < 6) return STBTT__CSERR(\"rcurveline stack\");\n         for (; i + 5 < sp; i += 6)\n            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);\n         break;\n\n      case 0x18: /*  rcurveline */\n         if (sp < 8) return STBTT__CSERR(\"rcurveline stack\");\n         for (; i + 5 < sp - 2; i += 6)\n            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);\n         if (i + 1 >= sp) return STBTT__CSERR(\"rcurveline stack\");\n         stbtt__csctx_rline_to(c, s[i], s[i+1]);\n         break;\n\n      case 0x19: /*  rlinecurve */\n         if (sp < 8) return STBTT__CSERR(\"rlinecurve stack\");\n         for (; i + 1 < sp - 6; i += 2)\n            stbtt__csctx_rline_to(c, s[i], s[i+1]);\n         if (i + 5 >= sp) return STBTT__CSERR(\"rlinecurve stack\");\n         stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);\n         break;\n\n      case 0x1A: /*  vvcurveto */\n      case 0x1B: /*  hhcurveto */\n         if (sp < 4) return STBTT__CSERR(\"(vv|hh)curveto stack\");\n         f = 0.0;\n         if (sp & 1) { f = s[i]; i++; }\n         for (; i + 3 < sp; i += 4) {\n            if (b0 == 0x1B)\n               stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);\n            else\n               stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);\n            f = 0.0;\n         }\n         break;\n\n      case 0x0A: /*  callsubr */\n         if (!has_subrs) {\n            if (info->fdselect.size)\n               subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);\n            has_subrs = 1;\n         }\n         /*  FALLTHROUGH */\n      case 0x1D: /*  callgsubr */\n         if (sp < 1) return STBTT__CSERR(\"call(g|)subr stack\");\n         v = (int) s[--sp];\n         if (subr_stack_height >= 10) return STBTT__CSERR(\"recursion limit\");\n         subr_stack[subr_stack_height++] = b;\n         b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);\n         if (b.size == 0) return STBTT__CSERR(\"subr not found\");\n         b.cursor = 0;\n         clear_stack = 0;\n         break;\n\n      case 0x0B: /*  return */\n         if (subr_stack_height <= 0) return STBTT__CSERR(\"return outside subr\");\n         b = subr_stack[--subr_stack_height];\n         clear_stack = 0;\n         break;\n\n      case 0x0E: /*  endchar */\n         stbtt__csctx_close_shape(c);\n         return 1;\n\n      case 0x0C: { /*  two-byte escape */\n         float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;\n         float dx, dy;\n         int b1 = stbtt__buf_get8(&b);\n         switch (b1) {\n         /*  @TODO These \"flex\" implementations ignore the flex-depth and resolution, */\n         /*  and always draw beziers. */\n         case 0x22: /*  hflex */\n            if (sp < 7) return STBTT__CSERR(\"hflex stack\");\n            dx1 = s[0];\n            dx2 = s[1];\n            dy2 = s[2];\n            dx3 = s[3];\n            dx4 = s[4];\n            dx5 = s[5];\n            dx6 = s[6];\n            stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);\n            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);\n            break;\n\n         case 0x23: /*  flex */\n            if (sp < 13) return STBTT__CSERR(\"flex stack\");\n            dx1 = s[0];\n            dy1 = s[1];\n            dx2 = s[2];\n            dy2 = s[3];\n            dx3 = s[4];\n            dy3 = s[5];\n            dx4 = s[6];\n            dy4 = s[7];\n            dx5 = s[8];\n            dy5 = s[9];\n            dx6 = s[10];\n            dy6 = s[11];\n            /* fd is s[12] */\n            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);\n            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);\n            break;\n\n         case 0x24: /*  hflex1 */\n            if (sp < 9) return STBTT__CSERR(\"hflex1 stack\");\n            dx1 = s[0];\n            dy1 = s[1];\n            dx2 = s[2];\n            dy2 = s[3];\n            dx3 = s[4];\n            dx4 = s[5];\n            dx5 = s[6];\n            dy5 = s[7];\n            dx6 = s[8];\n            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);\n            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));\n            break;\n\n         case 0x25: /*  flex1 */\n            if (sp < 11) return STBTT__CSERR(\"flex1 stack\");\n            dx1 = s[0];\n            dy1 = s[1];\n            dx2 = s[2];\n            dy2 = s[3];\n            dx3 = s[4];\n            dy3 = s[5];\n            dx4 = s[6];\n            dy4 = s[7];\n            dx5 = s[8];\n            dy5 = s[9];\n            dx6 = dy6 = s[10];\n            dx = dx1+dx2+dx3+dx4+dx5;\n            dy = dy1+dy2+dy3+dy4+dy5;\n            if (STBTT_fabs(dx) > STBTT_fabs(dy))\n               dy6 = -dy;\n            else\n               dx6 = -dx;\n            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);\n            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);\n            break;\n\n         default:\n            return STBTT__CSERR(\"unimplemented\");\n         }\n      } break;\n\n      default:\n         if (b0 != 255 && b0 != 28 && b0 < 32)\n            return STBTT__CSERR(\"reserved operator\");\n\n         /*  push immediate */\n         if (b0 == 255) {\n            f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;\n         } else {\n            stbtt__buf_skip(&b, -1);\n            f = (float)(stbtt_int16)stbtt__cff_int(&b);\n         }\n         if (sp >= 48) return STBTT__CSERR(\"push stack overflow\");\n         s[sp++] = f;\n         clear_stack = 0;\n         break;\n      }\n      if (clear_stack) sp = 0;\n   }\n   return STBTT__CSERR(\"no endchar\");\n\n#undef STBTT__CSERR\n}\n\nstatic int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)\n{\n   /*  runs the charstring twice, once to count and once to output (to avoid realloc) */\n   stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1);\n   stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);\n   if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {\n      *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);\n      output_ctx.pvertices = *pvertices;\n      if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {\n         STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices);\n         return output_ctx.num_vertices;\n      }\n   }\n   *pvertices = NULL;\n   return 0;\n}\n\nstatic int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)\n{\n   stbtt__csctx c = STBTT__CSCTX_INIT(1);\n   int r = stbtt__run_charstring(info, glyph_index, &c);\n   if (x0)  *x0 = r ? c.min_x : 0;\n   if (y0)  *y0 = r ? c.min_y : 0;\n   if (x1)  *x1 = r ? c.max_x : 0;\n   if (y1)  *y1 = r ? c.max_y : 0;\n   return r ? c.num_vertices : 0;\n}\n\nSTBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)\n{\n   if (!info->cff.size)\n      return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);\n   else\n      return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);\n}\n\nSTBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)\n{\n   stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);\n   if (glyph_index < numOfLongHorMetrics) {\n      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*glyph_index);\n      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);\n   } else {\n      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));\n      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));\n   }\n}\n\nSTBTT_DEF int  stbtt_GetKerningTableLength(const stbtt_fontinfo *info)\n{\n   stbtt_uint8 *data = info->data + info->kern;\n\n   /*  we only look at the first table. it must be 'horizontal' and format 0. */\n   if (!info->kern)\n      return 0;\n   if (ttUSHORT(data+2) < 1) /*  number of tables, need at least 1 */\n      return 0;\n   if (ttUSHORT(data+8) != 1) /*  horizontal flag must be set in format */\n      return 0;\n\n   return ttUSHORT(data+10);\n}\n\nSTBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length)\n{\n   stbtt_uint8 *data = info->data + info->kern;\n   int k, length;\n\n   /*  we only look at the first table. it must be 'horizontal' and format 0. */\n   if (!info->kern)\n      return 0;\n   if (ttUSHORT(data+2) < 1) /*  number of tables, need at least 1 */\n      return 0;\n   if (ttUSHORT(data+8) != 1) /*  horizontal flag must be set in format */\n      return 0;\n\n   length = ttUSHORT(data+10);\n   if (table_length < length)\n      length = table_length;\n\n   for (k = 0; k < length; k++)\n   {\n      table[k].glyph1 = ttUSHORT(data+18+(k*6));\n      table[k].glyph2 = ttUSHORT(data+20+(k*6));\n      table[k].advance = ttSHORT(data+22+(k*6));\n   }\n\n   return length;\n}\n\nstatic int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)\n{\n   stbtt_uint8 *data = info->data + info->kern;\n   stbtt_uint32 needle, straw;\n   int l, r, m;\n\n   /*  we only look at the first table. it must be 'horizontal' and format 0. */\n   if (!info->kern)\n      return 0;\n   if (ttUSHORT(data+2) < 1) /*  number of tables, need at least 1 */\n      return 0;\n   if (ttUSHORT(data+8) != 1) /*  horizontal flag must be set in format */\n      return 0;\n\n   l = 0;\n   r = ttUSHORT(data+10) - 1;\n   needle = glyph1 << 16 | glyph2;\n   while (l <= r) {\n      m = (l + r) >> 1;\n      straw = ttULONG(data+18+(m*6)); /*  note: unaligned read */\n      if (needle < straw)\n         r = m - 1;\n      else if (needle > straw)\n         l = m + 1;\n      else\n         return ttSHORT(data+22+(m*6));\n   }\n   return 0;\n}\n\nstatic stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)\n{\n   stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);\n   switch (coverageFormat) {\n      case 1: {\n         stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);\n\n         /*  Binary search. */\n         stbtt_int32 l=0, r=glyphCount-1, m;\n         int straw, needle=glyph;\n         while (l <= r) {\n            stbtt_uint8 *glyphArray = coverageTable + 4;\n            stbtt_uint16 glyphID;\n            m = (l + r) >> 1;\n            glyphID = ttUSHORT(glyphArray + 2 * m);\n            straw = glyphID;\n            if (needle < straw)\n               r = m - 1;\n            else if (needle > straw)\n               l = m + 1;\n            else {\n               return m;\n            }\n         }\n         break;\n      }\n\n      case 2: {\n         stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);\n         stbtt_uint8 *rangeArray = coverageTable + 4;\n\n         /*  Binary search. */\n         stbtt_int32 l=0, r=rangeCount-1, m;\n         int strawStart, strawEnd, needle=glyph;\n         while (l <= r) {\n            stbtt_uint8 *rangeRecord;\n            m = (l + r) >> 1;\n            rangeRecord = rangeArray + 6 * m;\n            strawStart = ttUSHORT(rangeRecord);\n            strawEnd = ttUSHORT(rangeRecord + 2);\n            if (needle < strawStart)\n               r = m - 1;\n            else if (needle > strawEnd)\n               l = m + 1;\n            else {\n               stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);\n               return startCoverageIndex + glyph - strawStart;\n            }\n         }\n         break;\n      }\n\n      default: return -1; /*  unsupported */\n   }\n\n   return -1;\n}\n\nstatic stbtt_int32  stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)\n{\n   stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);\n   switch (classDefFormat)\n   {\n      case 1: {\n         stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);\n         stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);\n         stbtt_uint8 *classDef1ValueArray = classDefTable + 6;\n\n         if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)\n            return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));\n         break;\n      }\n\n      case 2: {\n         stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);\n         stbtt_uint8 *classRangeRecords = classDefTable + 4;\n\n         /*  Binary search. */\n         stbtt_int32 l=0, r=classRangeCount-1, m;\n         int strawStart, strawEnd, needle=glyph;\n         while (l <= r) {\n            stbtt_uint8 *classRangeRecord;\n            m = (l + r) >> 1;\n            classRangeRecord = classRangeRecords + 6 * m;\n            strawStart = ttUSHORT(classRangeRecord);\n            strawEnd = ttUSHORT(classRangeRecord + 2);\n            if (needle < strawStart)\n               r = m - 1;\n            else if (needle > strawEnd)\n               l = m + 1;\n            else\n               return (stbtt_int32)ttUSHORT(classRangeRecord + 4);\n         }\n         break;\n      }\n\n      default:\n         return -1; /*  Unsupported definition type, return an error. */\n   }\n\n   /*  \"All glyphs not assigned to a class fall into class 0\". (OpenType spec) */\n   return 0;\n}\n\n/*  Define to STBTT_assert(x) if you want to break on unimplemented formats. */\n#define STBTT_GPOS_TODO_assert(x)\n\nstatic stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)\n{\n   stbtt_uint16 lookupListOffset;\n   stbtt_uint8 *lookupList;\n   stbtt_uint16 lookupCount;\n   stbtt_uint8 *data;\n   stbtt_int32 i, sti;\n\n   if (!info->gpos) return 0;\n\n   data = info->data + info->gpos;\n\n   if (ttUSHORT(data+0) != 1) return 0; /*  Major version 1 */\n   if (ttUSHORT(data+2) != 0) return 0; /*  Minor version 0 */\n\n   lookupListOffset = ttUSHORT(data+8);\n   lookupList = data + lookupListOffset;\n   lookupCount = ttUSHORT(lookupList);\n\n   for (i=0; i<lookupCount; ++i) {\n      stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);\n      stbtt_uint8 *lookupTable = lookupList + lookupOffset;\n\n      stbtt_uint16 lookupType = ttUSHORT(lookupTable);\n      stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);\n      stbtt_uint8 *subTableOffsets = lookupTable + 6;\n      if (lookupType != 2) /*  Pair Adjustment Positioning Subtable */\n         continue;\n\n      for (sti=0; sti<subTableCount; sti++) {\n         stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);\n         stbtt_uint8 *table = lookupTable + subtableOffset;\n         stbtt_uint16 posFormat = ttUSHORT(table);\n         stbtt_uint16 coverageOffset = ttUSHORT(table + 2);\n         stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);\n         if (coverageIndex == -1) continue;\n\n         switch (posFormat) {\n            case 1: {\n               stbtt_int32 l, r, m;\n               int straw, needle;\n               stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);\n               stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);\n               if (valueFormat1 == 4 && valueFormat2 == 0) { /*  Support more formats? */\n                  stbtt_int32 valueRecordPairSizeInBytes = 2;\n                  stbtt_uint16 pairSetCount = ttUSHORT(table + 8);\n                  stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);\n                  stbtt_uint8 *pairValueTable = table + pairPosOffset;\n                  stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);\n                  stbtt_uint8 *pairValueArray = pairValueTable + 2;\n\n                  if (coverageIndex >= pairSetCount) return 0;\n\n                  needle=glyph2;\n                  r=pairValueCount-1;\n                  l=0;\n\n                  /*  Binary search. */\n                  while (l <= r) {\n                     stbtt_uint16 secondGlyph;\n                     stbtt_uint8 *pairValue;\n                     m = (l + r) >> 1;\n                     pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;\n                     secondGlyph = ttUSHORT(pairValue);\n                     straw = secondGlyph;\n                     if (needle < straw)\n                        r = m - 1;\n                     else if (needle > straw)\n                        l = m + 1;\n                     else {\n                        stbtt_int16 xAdvance = ttSHORT(pairValue + 2);\n                        return xAdvance;\n                     }\n                  }\n               } else\n                  return 0;\n               break;\n            }\n\n            case 2: {\n               stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);\n               stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);\n               if (valueFormat1 == 4 && valueFormat2 == 0) { /*  Support more formats? */\n                  stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);\n                  stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);\n                  int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);\n                  int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);\n\n                  stbtt_uint16 class1Count = ttUSHORT(table + 12);\n                  stbtt_uint16 class2Count = ttUSHORT(table + 14);\n                  stbtt_uint8 *class1Records, *class2Records;\n                  stbtt_int16 xAdvance;\n\n                  if (glyph1class < 0 || glyph1class >= class1Count) return 0; /*  malformed */\n                  if (glyph2class < 0 || glyph2class >= class2Count) return 0; /*  malformed */\n\n                  class1Records = table + 16;\n                  class2Records = class1Records + 2 * (glyph1class * class2Count);\n                  xAdvance = ttSHORT(class2Records + 2 * glyph2class);\n                  return xAdvance;\n               } else\n                  return 0;\n               break;\n            }\n\n            default:\n               return 0; /*  Unsupported position format */\n         }\n      }\n   }\n\n   return 0;\n}\n\nSTBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)\n{\n   int xAdvance = 0;\n\n   if (info->gpos)\n      xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);\n   else if (info->kern)\n      xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);\n\n   return xAdvance;\n}\n\nSTBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)\n{\n   if (!info->kern && !info->gpos) /*  if no kerning table, don't waste time looking up both codepoint->glyphs */\n      return 0;\n   return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));\n}\n\nSTBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)\n{\n   stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);\n}\n\nSTBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)\n{\n   if (ascent ) *ascent  = ttSHORT(info->data+info->hhea + 4);\n   if (descent) *descent = ttSHORT(info->data+info->hhea + 6);\n   if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);\n}\n\nSTBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap)\n{\n   int tab = stbtt__find_table(info->data, info->fontstart, \"OS/2\");\n   if (!tab)\n      return 0;\n   if (typoAscent ) *typoAscent  = ttSHORT(info->data+tab + 68);\n   if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);\n   if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);\n   return 1;\n}\n\nSTBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)\n{\n   *x0 = ttSHORT(info->data + info->head + 36);\n   *y0 = ttSHORT(info->data + info->head + 38);\n   *x1 = ttSHORT(info->data + info->head + 40);\n   *y1 = ttSHORT(info->data + info->head + 42);\n}\n\nSTBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)\n{\n   int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);\n   return (float) height / fheight;\n}\n\nSTBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels)\n{\n   int unitsPerEm = ttUSHORT(info->data + info->head + 18);\n   return pixels / unitsPerEm;\n}\n\nSTBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)\n{\n   STBTT_free(v, info->userdata);\n}\n\nSTBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl)\n{\n   int i;\n   stbtt_uint8 *data = info->data;\n   stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info);\n\n   int numEntries = ttUSHORT(svg_doc_list);\n   stbtt_uint8 *svg_docs = svg_doc_list + 2;\n\n   for(i=0; i<numEntries; i++) {\n      stbtt_uint8 *svg_doc = svg_docs + (12 * i);\n      if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2)))\n         return svg_doc;\n   }\n   return 0;\n}\n\nSTBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg)\n{\n   stbtt_uint8 *data = info->data;\n   stbtt_uint8 *svg_doc;\n\n   if (info->svg == 0)\n      return 0;\n\n   svg_doc = stbtt_FindSVGDoc(info, gl);\n   if (svg_doc != NULL) {\n      *svg = (char *) data + info->svg + ttULONG(svg_doc + 4);\n      return ttULONG(svg_doc + 8);\n   } else {\n      return 0;\n   }\n}\n\nSTBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg)\n{\n   return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg);\n}\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  antialiasing software rasterizer */\n/*  */\n\nSTBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)\n{\n   int x0=0,y0=0,x1,y1; /*  =0 suppresses compiler warning */\n   if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {\n      /*  e.g. space character */\n      if (ix0) *ix0 = 0;\n      if (iy0) *iy0 = 0;\n      if (ix1) *ix1 = 0;\n      if (iy1) *iy1 = 0;\n   } else {\n      /*  move to integral bboxes (treating pixels as little squares, what pixels get touched)? */\n      if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);\n      if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);\n      if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);\n      if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);\n   }\n}\n\nSTBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)\n{\n   stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);\n}\n\nSTBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)\n{\n   stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);\n}\n\nSTBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)\n{\n   stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);\n}\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*   Rasterizer */\n\ntypedef struct stbtt__hheap_chunk\n{\n   struct stbtt__hheap_chunk *next;\n} stbtt__hheap_chunk;\n\ntypedef struct stbtt__hheap\n{\n   struct stbtt__hheap_chunk *head;\n   void   *first_free;\n   int    num_remaining_in_head_chunk;\n} stbtt__hheap;\n\nstatic void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)\n{\n   if (hh->first_free) {\n      void *p = hh->first_free;\n      hh->first_free = * (void **) p;\n      return p;\n   } else {\n      if (hh->num_remaining_in_head_chunk == 0) {\n         int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);\n         stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);\n         if (c == NULL)\n            return NULL;\n         c->next = hh->head;\n         hh->head = c;\n         hh->num_remaining_in_head_chunk = count;\n      }\n      --hh->num_remaining_in_head_chunk;\n      return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;\n   }\n}\n\nstatic void stbtt__hheap_free(stbtt__hheap *hh, void *p)\n{\n   *(void **) p = hh->first_free;\n   hh->first_free = p;\n}\n\nstatic void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)\n{\n   stbtt__hheap_chunk *c = hh->head;\n   while (c) {\n      stbtt__hheap_chunk *n = c->next;\n      STBTT_free(c, userdata);\n      c = n;\n   }\n}\n\ntypedef struct stbtt__edge {\n   float x0,y0, x1,y1;\n   int invert;\n} stbtt__edge;\n\n\ntypedef struct stbtt__active_edge\n{\n   struct stbtt__active_edge *next;\n   #if STBTT_RASTERIZER_VERSION==1\n   int x,dx;\n   float ey;\n   int direction;\n   #elif STBTT_RASTERIZER_VERSION==2\n   float fx,fdx,fdy;\n   float direction;\n   float sy;\n   float ey;\n   #else\n   #error \"Unrecognized value of STBTT_RASTERIZER_VERSION\"\n   #endif\n} stbtt__active_edge;\n\n#if STBTT_RASTERIZER_VERSION == 1\n#define STBTT_FIXSHIFT   10\n#define STBTT_FIX        (1 << STBTT_FIXSHIFT)\n#define STBTT_FIXMASK    (STBTT_FIX-1)\n\nstatic stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)\n{\n   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);\n   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);\n   STBTT_assert(z != NULL);\n   if (!z) return z;\n\n   /*  round dx down to avoid overshooting */\n   if (dxdy < 0)\n      z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);\n   else\n      z->dx = STBTT_ifloor(STBTT_FIX * dxdy);\n\n   z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); /*  use z->dx so when we offset later it's by the same amount */\n   z->x -= off_x * STBTT_FIX;\n\n   z->ey = e->y1;\n   z->next = 0;\n   z->direction = e->invert ? 1 : -1;\n   return z;\n}\n#elif STBTT_RASTERIZER_VERSION == 2\nstatic stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)\n{\n   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);\n   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);\n   STBTT_assert(z != NULL);\n   /* STBTT_assert(e->y0 <= start_point); */\n   if (!z) return z;\n   z->fdx = dxdy;\n   z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;\n   z->fx = e->x0 + dxdy * (start_point - e->y0);\n   z->fx -= off_x;\n   z->direction = e->invert ? 1.0f : -1.0f;\n   z->sy = e->y0;\n   z->ey = e->y1;\n   z->next = 0;\n   return z;\n}\n#else\n#error \"Unrecognized value of STBTT_RASTERIZER_VERSION\"\n#endif\n\n#if STBTT_RASTERIZER_VERSION == 1\n/*  note: this routine clips fills that extend off the edges... ideally this */\n/*  wouldn't happen, but it could happen if the truetype glyph bounding boxes */\n/*  are wrong, or if the user supplies a too-small bitmap */\nstatic void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)\n{\n   /*  non-zero winding fill */\n   int x0=0, w=0;\n\n   while (e) {\n      if (w == 0) {\n         /*  if we're currently at zero, we need to record the edge start point */\n         x0 = e->x; w += e->direction;\n      } else {\n         int x1 = e->x; w += e->direction;\n         /*  if we went to zero, we need to draw */\n         if (w == 0) {\n            int i = x0 >> STBTT_FIXSHIFT;\n            int j = x1 >> STBTT_FIXSHIFT;\n\n            if (i < len && j >= 0) {\n               if (i == j) {\n                  /*  x0,x1 are the same pixel, so compute combined coverage */\n                  scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);\n               } else {\n                  if (i >= 0) /*  add antialiasing for x0 */\n                     scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);\n                  else\n                     i = -1; /*  clip */\n\n                  if (j < len) /*  add antialiasing for x1 */\n                     scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);\n                  else\n                     j = len; /*  clip */\n\n                  for (++i; i < j; ++i) /*  fill pixels between x0 and x1 */\n                     scanline[i] = scanline[i] + (stbtt_uint8) max_weight;\n               }\n            }\n         }\n      }\n\n      e = e->next;\n   }\n}\n\nstatic void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)\n{\n   stbtt__hheap hh = { 0, 0, 0 };\n   stbtt__active_edge *active = NULL;\n   int y,j=0;\n   int max_weight = (255 / vsubsample);  /*  weight per vertical scanline */\n   int s; /*  vertical subsample index */\n   unsigned char scanline_data[512], *scanline;\n\n   if (result->w > 512)\n      scanline = (unsigned char *) STBTT_malloc(result->w, userdata);\n   else\n      scanline = scanline_data;\n\n   y = off_y * vsubsample;\n   e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;\n\n   while (j < result->h) {\n      STBTT_memset(scanline, 0, result->w);\n      for (s=0; s < vsubsample; ++s) {\n         /*  find center of pixel for this scanline */\n         float scan_y = y + 0.5f;\n         stbtt__active_edge **step = &active;\n\n         /*  update all active edges; */\n         /*  remove all active edges that terminate before the center of this scanline */\n         while (*step) {\n            stbtt__active_edge * z = *step;\n            if (z->ey <= scan_y) {\n               *step = z->next; /*  delete from list */\n               STBTT_assert(z->direction);\n               z->direction = 0;\n               stbtt__hheap_free(&hh, z);\n            } else {\n               z->x += z->dx; /*  advance to position for current scanline */\n               step = &((*step)->next); /*  advance through list */\n            }\n         }\n\n         /*  resort the list if needed */\n         for(;;) {\n            int changed=0;\n            step = &active;\n            while (*step && (*step)->next) {\n               if ((*step)->x > (*step)->next->x) {\n                  stbtt__active_edge *t = *step;\n                  stbtt__active_edge *q = t->next;\n\n                  t->next = q->next;\n                  q->next = t;\n                  *step = q;\n                  changed = 1;\n               }\n               step = &(*step)->next;\n            }\n            if (!changed) break;\n         }\n\n         /*  insert all edges that start before the center of this scanline -- omit ones that also end on this scanline */\n         while (e->y0 <= scan_y) {\n            if (e->y1 > scan_y) {\n               stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);\n               if (z != NULL) {\n                  /*  find insertion point */\n                  if (active == NULL)\n                     active = z;\n                  else if (z->x < active->x) {\n                     /*  insert at front */\n                     z->next = active;\n                     active = z;\n                  } else {\n                     /*  find thing to insert AFTER */\n                     stbtt__active_edge *p = active;\n                     while (p->next && p->next->x < z->x)\n                        p = p->next;\n                     /*  at this point, p->next->x is NOT < z->x */\n                     z->next = p->next;\n                     p->next = z;\n                  }\n               }\n            }\n            ++e;\n         }\n\n         /*  now process all active edges in XOR fashion */\n         if (active)\n            stbtt__fill_active_edges(scanline, result->w, active, max_weight);\n\n         ++y;\n      }\n      STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);\n      ++j;\n   }\n\n   stbtt__hheap_cleanup(&hh, userdata);\n\n   if (scanline != scanline_data)\n      STBTT_free(scanline, userdata);\n}\n\n#elif STBTT_RASTERIZER_VERSION == 2\n\n/*  the edge passed in here does not cross the vertical line at x or the vertical line at x+1 */\n/*  (i.e. it has already been clipped to those) */\nstatic void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)\n{\n   if (y0 == y1) return;\n   STBTT_assert(y0 < y1);\n   STBTT_assert(e->sy <= e->ey);\n   if (y0 > e->ey) return;\n   if (y1 < e->sy) return;\n   if (y0 < e->sy) {\n      x0 += (x1-x0) * (e->sy - y0) / (y1-y0);\n      y0 = e->sy;\n   }\n   if (y1 > e->ey) {\n      x1 += (x1-x0) * (e->ey - y1) / (y1-y0);\n      y1 = e->ey;\n   }\n\n   if (x0 == x)\n      STBTT_assert(x1 <= x+1);\n   else if (x0 == x+1)\n      STBTT_assert(x1 >= x);\n   else if (x0 <= x)\n      STBTT_assert(x1 <= x);\n   else if (x0 >= x+1)\n      STBTT_assert(x1 >= x+1);\n   else\n      STBTT_assert(x1 >= x && x1 <= x+1);\n\n   if (x0 <= x && x1 <= x)\n      scanline[x] += e->direction * (y1-y0);\n   else if (x0 >= x+1 && x1 >= x+1)\n      ;\n   else {\n      STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);\n      scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); /*  coverage = 1 - average x position */\n   }\n}\n\nstatic float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width)\n{\n   STBTT_assert(top_width >= 0);\n   STBTT_assert(bottom_width >= 0);\n   return (top_width + bottom_width) / 2.0f * height;\n}\n\nstatic float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1)\n{\n   return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);\n}\n\nstatic float stbtt__sized_triangle_area(float height, float width)\n{\n   return height * width / 2;\n}\n\nstatic void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)\n{\n   float y_bottom = y_top+1;\n\n   while (e) {\n      /*  brute force every pixel */\n\n      /*  compute intersection points with top & bottom */\n      STBTT_assert(e->ey >= y_top);\n\n      if (e->fdx == 0) {\n         float x0 = e->fx;\n         if (x0 < len) {\n            if (x0 >= 0) {\n               stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);\n               stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);\n            } else {\n               stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);\n            }\n         }\n      } else {\n         float x0 = e->fx;\n         float dx = e->fdx;\n         float xb = x0 + dx;\n         float x_top, x_bottom;\n         float sy0,sy1;\n         float dy = e->fdy;\n         STBTT_assert(e->sy <= y_bottom && e->ey >= y_top);\n\n         /*  compute endpoints of line segment clipped to this scanline (if the */\n         /*  line segment starts on this scanline. x0 is the intersection of the */\n         /*  line with y_top, but that may be off the line segment. */\n         if (e->sy > y_top) {\n            x_top = x0 + dx * (e->sy - y_top);\n            sy0 = e->sy;\n         } else {\n            x_top = x0;\n            sy0 = y_top;\n         }\n         if (e->ey < y_bottom) {\n            x_bottom = x0 + dx * (e->ey - y_top);\n            sy1 = e->ey;\n         } else {\n            x_bottom = xb;\n            sy1 = y_bottom;\n         }\n\n         if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {\n            /*  from here on, we don't have to range check x values */\n\n            if ((int) x_top == (int) x_bottom) {\n               float height;\n               /*  simple case, only spans one pixel */\n               int x = (int) x_top;\n               height = (sy1 - sy0) * e->direction;\n               STBTT_assert(x >= 0 && x < len);\n               scanline[x]      += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);\n               scanline_fill[x] += height; /*  everything right of this pixel is filled */\n            } else {\n               int x,x1,x2;\n               float y_crossing, y_final, step, sign, area;\n               /*  covers 2+ pixels */\n               if (x_top > x_bottom) {\n                  /*  flip scanline vertically; signed area is the same */\n                  float t;\n                  sy0 = y_bottom - (sy0 - y_top);\n                  sy1 = y_bottom - (sy1 - y_top);\n                  t = sy0, sy0 = sy1, sy1 = t;\n                  t = x_bottom, x_bottom = x_top, x_top = t;\n                  dx = -dx;\n                  dy = -dy;\n                  t = x0, x0 = xb, xb = t;\n               }\n               STBTT_assert(dy >= 0);\n               STBTT_assert(dx >= 0);\n\n               x1 = (int) x_top;\n               x2 = (int) x_bottom;\n               /*  compute intersection with y axis at x1+1 */\n               y_crossing = y_top + dy * (x1+1 - x0);\n\n               /*  compute intersection with y axis at x2 */\n               y_final = y_top + dy * (x2 - x0);\n\n               /*            x1    x_top                            x2    x_bottom */\n               /*      y_top  +------|-----+------------+------------+--------|---+------------+ */\n               /*             |            |            |            |            |            | */\n               /*             |            |            |            |            |            | */\n               /*        sy0  |      Txxxxx|............|............|............|............| */\n               /*  y_crossing |            *xxxxx.......|............|............|............| */\n               /*             |            |     xxxxx..|............|............|............| */\n               /*             |            |     /-   xx*xxxx........|............|............| */\n               /*             |            | dy <       |    xxxxxx..|............|............| */\n               /*    y_final  |            |     \\-     |          xx*xxx.........|............| */\n               /*        sy1  |            |            |            |   xxxxxB...|............| */\n               /*             |            |            |            |            |            | */\n               /*             |            |            |            |            |            | */\n               /*   y_bottom  +------------+------------+------------+------------+------------+ */\n               /*  */\n               /*  goal is to measure the area covered by '.' in each pixel */\n\n               /*  if x2 is right at the right edge of x1, y_crossing can blow up, github #1057 */\n               /*  @TODO: maybe test against sy1 rather than y_bottom? */\n               if (y_crossing > y_bottom)\n                  y_crossing = y_bottom;\n\n               sign = e->direction;\n\n               /*  area of the rectangle covered from sy0..y_crossing */\n               area = sign * (y_crossing-sy0);\n\n               /*  area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing) */\n               scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);\n\n               /*  check if final y_crossing is blown up; no test case for this */\n               if (y_final > y_bottom) {\n                  y_final = y_bottom;\n                  dy = (y_final - y_crossing ) / (x2 - (x1+1)); /*  if denom=0, y_final = y_crossing, so y_final <= y_bottom */\n               }\n\n               /*  in second pixel, area covered by line segment found in first pixel */\n               /*  is always a rectangle 1 wide * the height of that line segment; this */\n               /*  is exactly what the variable 'area' stores. it also gets a contribution */\n               /*  from the line segment within it. the THIRD pixel will get the first */\n               /*  pixel's rectangle contribution, the second pixel's rectangle contribution, */\n               /*  and its own contribution. the 'own contribution' is the same in every pixel except */\n               /*  the leftmost and rightmost, a trapezoid that slides down in each pixel. */\n               /*  the second pixel's contribution to the third pixel will be the */\n               /*  rectangle 1 wide times the height change in the second pixel, which is dy. */\n\n               step = sign * dy * 1; /*  dy is dy/dx, change in y for every 1 change in x, */\n               /*  which multiplied by 1-pixel-width is how much pixel area changes for each step in x */\n               /*  so the area advances by 'step' every time */\n\n               for (x = x1+1; x < x2; ++x) {\n                  scanline[x] += area + step/2; /*  area of trapezoid is 1*step/2 */\n                  area += step;\n               }\n               STBTT_assert(STBTT_fabs(area) <= 1.01f); /*  accumulated error from area += step unless we round step down */\n               STBTT_assert(sy1 > y_final-0.01f);\n\n               /*  area covered in the last pixel is the rectangle from all the pixels to the left, */\n               /*  plus the trapezoid filled by the line segment in this pixel all the way to the right edge */\n               scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f);\n\n               /*  the rest of the line is filled based on the total height of the line segment in this pixel */\n               scanline_fill[x2] += sign * (sy1-sy0);\n            }\n         } else {\n            /*  if edge goes outside of box we're drawing, we require */\n            /*  clipping logic. since this does not match the intended use */\n            /*  of this library, we use a different, very slow brute */\n            /*  force implementation */\n            /*  note though that this does happen some of the time because */\n            /*  x_top and x_bottom can be extrapolated at the top & bottom of */\n            /*  the shape and actually lie outside the bounding box */\n            int x;\n            for (x=0; x < len; ++x) {\n               /*  cases: */\n               /*  */\n               /*  there can be up to two intersections with the pixel. any intersection */\n               /*  with left or right edges can be handled by splitting into two (or three) */\n               /*  regions. intersections with top & bottom do not necessitate case-wise logic. */\n               /*  */\n               /*  the old way of doing this found the intersections with the left & right edges, */\n               /*  then used some simple logic to produce up to three segments in sorted order */\n               /*  from top-to-bottom. however, this had a problem: if an x edge was epsilon */\n               /*  across the x border, then the corresponding y position might not be distinct */\n               /*  from the other y segment, and it might ignored as an empty segment. to avoid */\n               /*  that, we need to explicitly produce segments based on x positions. */\n\n               /*  rename variables to clearly-defined pairs */\n               float y0 = y_top;\n               float x1 = (float) (x);\n               float x2 = (float) (x+1);\n               float x3 = xb;\n               float y3 = y_bottom;\n\n               /*  x = e->x + e->dx * (y-y_top) */\n               /*  (y-y_top) = (x - e->x) / e->dx */\n               /*  y = (x - e->x) / e->dx + y_top */\n               float y1 = (x - x0) / dx + y_top;\n               float y2 = (x+1 - x0) / dx + y_top;\n\n               if (x0 < x1 && x3 > x2) {         /*  three segments descending down-right */\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);\n                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);\n                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);\n               } else if (x3 < x1 && x0 > x2) {  /*  three segments descending down-left */\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);\n                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);\n                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);\n               } else if (x0 < x1 && x3 > x1) {  /*  two segments across x, down-right */\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);\n                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);\n               } else if (x3 < x1 && x0 > x1) {  /*  two segments across x, down-left */\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);\n                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);\n               } else if (x0 < x2 && x3 > x2) {  /*  two segments across x+1, down-right */\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);\n                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);\n               } else if (x3 < x2 && x0 > x2) {  /*  two segments across x+1, down-left */\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);\n                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);\n               } else {  /*  one segment */\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);\n               }\n            }\n         }\n      }\n      e = e->next;\n   }\n}\n\n/*  directly AA rasterize edges w/o supersampling */\nstatic void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)\n{\n   stbtt__hheap hh = { 0, 0, 0 };\n   stbtt__active_edge *active = NULL;\n   int y,j=0, i;\n   float scanline_data[129], *scanline, *scanline2;\n\n   STBTT__NOTUSED(vsubsample);\n\n   if (result->w > 64)\n      scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);\n   else\n      scanline = scanline_data;\n\n   scanline2 = scanline + result->w;\n\n   y = off_y;\n   e[n].y0 = (float) (off_y + result->h) + 1;\n\n   while (j < result->h) {\n      /*  find center of pixel for this scanline */\n      float scan_y_top    = y + 0.0f;\n      float scan_y_bottom = y + 1.0f;\n      stbtt__active_edge **step = &active;\n\n      STBTT_memset(scanline , 0, result->w*sizeof(scanline[0]));\n      STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0]));\n\n      /*  update all active edges; */\n      /*  remove all active edges that terminate before the top of this scanline */\n      while (*step) {\n         stbtt__active_edge * z = *step;\n         if (z->ey <= scan_y_top) {\n            *step = z->next; /*  delete from list */\n            STBTT_assert(z->direction);\n            z->direction = 0;\n            stbtt__hheap_free(&hh, z);\n         } else {\n            step = &((*step)->next); /*  advance through list */\n         }\n      }\n\n      /*  insert all edges that start before the bottom of this scanline */\n      while (e->y0 <= scan_y_bottom) {\n         if (e->y0 != e->y1) {\n            stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);\n            if (z != NULL) {\n               if (j == 0 && off_y != 0) {\n                  if (z->ey < scan_y_top) {\n                     /*  this can happen due to subpixel positioning and some kind of fp rounding error i think */\n                     z->ey = scan_y_top;\n                  }\n               }\n               STBTT_assert(z->ey >= scan_y_top); /*  if we get really unlucky a tiny bit of an edge can be out of bounds */\n               /*  insert at front */\n               z->next = active;\n               active = z;\n            }\n         }\n         ++e;\n      }\n\n      /*  now process all active edges */\n      if (active)\n         stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);\n\n      {\n         float sum = 0;\n         for (i=0; i < result->w; ++i) {\n            float k;\n            int m;\n            sum += scanline2[i];\n            k = scanline[i] + sum;\n            k = (float) STBTT_fabs(k)*255 + 0.5f;\n            m = (int) k;\n            if (m > 255) m = 255;\n            result->pixels[j*result->stride + i] = (unsigned char) m;\n         }\n      }\n      /*  advance all the edges */\n      step = &active;\n      while (*step) {\n         stbtt__active_edge *z = *step;\n         z->fx += z->fdx; /*  advance to position for current scanline */\n         step = &((*step)->next); /*  advance through list */\n      }\n\n      ++y;\n      ++j;\n   }\n\n   stbtt__hheap_cleanup(&hh, userdata);\n\n   if (scanline != scanline_data)\n      STBTT_free(scanline, userdata);\n}\n#else\n#error \"Unrecognized value of STBTT_RASTERIZER_VERSION\"\n#endif\n\n#define STBTT__COMPARE(a,b)  ((a)->y0 < (b)->y0)\n\nstatic void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)\n{\n   int i,j;\n   for (i=1; i < n; ++i) {\n      stbtt__edge t = p[i], *a = &t;\n      j = i;\n      while (j > 0) {\n         stbtt__edge *b = &p[j-1];\n         int c = STBTT__COMPARE(a,b);\n         if (!c) break;\n         p[j] = p[j-1];\n         --j;\n      }\n      if (i != j)\n         p[j] = t;\n   }\n}\n\nstatic void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)\n{\n   /* threshold for transitioning to insertion sort */\n   while (n > 12) {\n      stbtt__edge t;\n      int c01,c12,c,m,i,j;\n\n      /* compute median of three */\n      m = n >> 1;\n      c01 = STBTT__COMPARE(&p[0],&p[m]);\n      c12 = STBTT__COMPARE(&p[m],&p[n-1]);\n      /* if 0 >= mid >= end, or 0 < mid < end, then use mid */\n      if (c01 != c12) {\n         /* otherwise, we'll need to swap something else to middle */\n         int z;\n         c = STBTT__COMPARE(&p[0],&p[n-1]);\n         /* 0>mid && mid<n:  0>n => n; 0<n => 0 */\n         /* 0<mid && mid>n:  0>n => 0; 0<n => n */\n         z = (c == c12) ? 0 : n-1;\n         t = p[z];\n         p[z] = p[m];\n         p[m] = t;\n      }\n      /* now p[m] is the median-of-three */\n      /* swap it to the beginning so it won't move around */\n      t = p[0];\n      p[0] = p[m];\n      p[m] = t;\n\n      /* partition loop */\n      i=1;\n      j=n-1;\n      for(;;) {\n         /* handling of equality is crucial here */\n         /* for sentinels & efficiency with duplicates */\n         for (;;++i) {\n            if (!STBTT__COMPARE(&p[i], &p[0])) break;\n         }\n         for (;;--j) {\n            if (!STBTT__COMPARE(&p[0], &p[j])) break;\n         }\n         /* make sure we haven't crossed */\n         if (i >= j) break;\n         t = p[i];\n         p[i] = p[j];\n         p[j] = t;\n\n         ++i;\n         --j;\n      }\n      /* recurse on smaller side, iterate on larger */\n      if (j < (n-i)) {\n         stbtt__sort_edges_quicksort(p,j);\n         p = p+i;\n         n = n-i;\n      } else {\n         stbtt__sort_edges_quicksort(p+i, n-i);\n         n = j;\n      }\n   }\n}\n\nstatic void stbtt__sort_edges(stbtt__edge *p, int n)\n{\n   stbtt__sort_edges_quicksort(p, n);\n   stbtt__sort_edges_ins_sort(p, n);\n}\n\ntypedef struct\n{\n   float x,y;\n} stbtt__point;\n\nstatic void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata)\n{\n   float y_scale_inv = invert ? -scale_y : scale_y;\n   stbtt__edge *e;\n   int n,i,j,k,m;\n#if STBTT_RASTERIZER_VERSION == 1\n   int vsubsample = result->h < 8 ? 15 : 5;\n#elif STBTT_RASTERIZER_VERSION == 2\n   int vsubsample = 1;\n#else\n   #error \"Unrecognized value of STBTT_RASTERIZER_VERSION\"\n#endif\n   /*  vsubsample should divide 255 evenly; otherwise we won't reach full opacity */\n\n   /*  now we have to blow out the windings into explicit edge lists */\n   n = 0;\n   for (i=0; i < windings; ++i)\n      n += wcount[i];\n\n   e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); /*  add an extra one as a sentinel */\n   if (e == 0) return;\n   n = 0;\n\n   m=0;\n   for (i=0; i < windings; ++i) {\n      stbtt__point *p = pts + m;\n      m += wcount[i];\n      j = wcount[i]-1;\n      for (k=0; k < wcount[i]; j=k++) {\n         int a=k,b=j;\n         /*  skip the edge if horizontal */\n         if (p[j].y == p[k].y)\n            continue;\n         /*  add edge from j to k to the list */\n         e[n].invert = 0;\n         if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {\n            e[n].invert = 1;\n            a=j,b=k;\n         }\n         e[n].x0 = p[a].x * scale_x + shift_x;\n         e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;\n         e[n].x1 = p[b].x * scale_x + shift_x;\n         e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;\n         ++n;\n      }\n   }\n\n   /*  now sort the edges by their highest point (should snap to integer, and then by x) */\n   /* STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare); */\n   stbtt__sort_edges(e, n);\n\n   /*  now, traverse the scanlines and find the intersections on each scanline, use xor winding rule */\n   stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);\n\n   STBTT_free(e, userdata);\n}\n\nstatic void stbtt__add_point(stbtt__point *points, int n, float x, float y)\n{\n   if (!points) return; /*  during first pass, it's unallocated */\n   points[n].x = x;\n   points[n].y = y;\n}\n\n/*  tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching */\nstatic int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)\n{\n   /*  midpoint */\n   float mx = (x0 + 2*x1 + x2)/4;\n   float my = (y0 + 2*y1 + y2)/4;\n   /*  versus directly drawn line */\n   float dx = (x0+x2)/2 - mx;\n   float dy = (y0+y2)/2 - my;\n   if (n > 16) /*  65536 segments on one curve better be enough! */\n      return 1;\n   if (dx*dx+dy*dy > objspace_flatness_squared) { /*  half-pixel error allowed... need to be smaller if AA */\n      stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);\n      stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);\n   } else {\n      stbtt__add_point(points, *num_points,x2,y2);\n      *num_points = *num_points+1;\n   }\n   return 1;\n}\n\nstatic void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n)\n{\n   /*  @TODO this \"flatness\" calculation is just made-up nonsense that seems to work well enough */\n   float dx0 = x1-x0;\n   float dy0 = y1-y0;\n   float dx1 = x2-x1;\n   float dy1 = y2-y1;\n   float dx2 = x3-x2;\n   float dy2 = y3-y2;\n   float dx = x3-x0;\n   float dy = y3-y0;\n   float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));\n   float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);\n   float flatness_squared = longlen*longlen-shortlen*shortlen;\n\n   if (n > 16) /*  65536 segments on one curve better be enough! */\n      return;\n\n   if (flatness_squared > objspace_flatness_squared) {\n      float x01 = (x0+x1)/2;\n      float y01 = (y0+y1)/2;\n      float x12 = (x1+x2)/2;\n      float y12 = (y1+y2)/2;\n      float x23 = (x2+x3)/2;\n      float y23 = (y2+y3)/2;\n\n      float xa = (x01+x12)/2;\n      float ya = (y01+y12)/2;\n      float xb = (x12+x23)/2;\n      float yb = (y12+y23)/2;\n\n      float mx = (xa+xb)/2;\n      float my = (ya+yb)/2;\n\n      stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);\n      stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);\n   } else {\n      stbtt__add_point(points, *num_points,x3,y3);\n      *num_points = *num_points+1;\n   }\n}\n\n/*  returns number of contours */\nstatic stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)\n{\n   stbtt__point *points=0;\n   int num_points=0;\n\n   float objspace_flatness_squared = objspace_flatness * objspace_flatness;\n   int i,n=0,start=0, pass;\n\n   /*  count how many \"moves\" there are to get the contour count */\n   for (i=0; i < num_verts; ++i)\n      if (vertices[i].type == STBTT_vmove)\n         ++n;\n\n   *num_contours = n;\n   if (n == 0) return 0;\n\n   *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);\n\n   if (*contour_lengths == 0) {\n      *num_contours = 0;\n      return 0;\n   }\n\n   /*  make two passes through the points so we don't need to realloc */\n   for (pass=0; pass < 2; ++pass) {\n      float x=0,y=0;\n      if (pass == 1) {\n         points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);\n         if (points == NULL) goto error;\n      }\n      num_points = 0;\n      n= -1;\n      for (i=0; i < num_verts; ++i) {\n         switch (vertices[i].type) {\n            case STBTT_vmove:\n               /*  start the next contour */\n               if (n >= 0)\n                  (*contour_lengths)[n] = num_points - start;\n               ++n;\n               start = num_points;\n\n               x = vertices[i].x, y = vertices[i].y;\n               stbtt__add_point(points, num_points++, x,y);\n               break;\n            case STBTT_vline:\n               x = vertices[i].x, y = vertices[i].y;\n               stbtt__add_point(points, num_points++, x, y);\n               break;\n            case STBTT_vcurve:\n               stbtt__tesselate_curve(points, &num_points, x,y,\n                                        vertices[i].cx, vertices[i].cy,\n                                        vertices[i].x,  vertices[i].y,\n                                        objspace_flatness_squared, 0);\n               x = vertices[i].x, y = vertices[i].y;\n               break;\n            case STBTT_vcubic:\n               stbtt__tesselate_cubic(points, &num_points, x,y,\n                                        vertices[i].cx, vertices[i].cy,\n                                        vertices[i].cx1, vertices[i].cy1,\n                                        vertices[i].x,  vertices[i].y,\n                                        objspace_flatness_squared, 0);\n               x = vertices[i].x, y = vertices[i].y;\n               break;\n         }\n      }\n      (*contour_lengths)[n] = num_points - start;\n   }\n\n   return points;\nerror:\n   STBTT_free(points, userdata);\n   STBTT_free(*contour_lengths, userdata);\n   *contour_lengths = 0;\n   *num_contours = 0;\n   return NULL;\n}\n\nSTBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)\n{\n   float scale            = scale_x > scale_y ? scale_y : scale_x;\n   int winding_count      = 0;\n   int *winding_lengths   = NULL;\n   stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);\n   if (windings) {\n      stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);\n      STBTT_free(winding_lengths, userdata);\n      STBTT_free(windings, userdata);\n   }\n}\n\nSTBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)\n{\n   STBTT_free(bitmap, userdata);\n}\n\nSTBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)\n{\n   int ix0,iy0,ix1,iy1;\n   stbtt__bitmap gbm;\n   stbtt_vertex *vertices;\n   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);\n\n   if (scale_x == 0) scale_x = scale_y;\n   if (scale_y == 0) {\n      if (scale_x == 0) {\n         STBTT_free(vertices, info->userdata);\n         return NULL;\n      }\n      scale_y = scale_x;\n   }\n\n   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);\n\n   /*  now we get the size */\n   gbm.w = (ix1 - ix0);\n   gbm.h = (iy1 - iy0);\n   gbm.pixels = NULL; /*  in case we error */\n\n   if (width ) *width  = gbm.w;\n   if (height) *height = gbm.h;\n   if (xoff  ) *xoff   = ix0;\n   if (yoff  ) *yoff   = iy0;\n\n   if (gbm.w && gbm.h) {\n      gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);\n      if (gbm.pixels) {\n         gbm.stride = gbm.w;\n\n         stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);\n      }\n   }\n   STBTT_free(vertices, info->userdata);\n   return gbm.pixels;\n}\n\nSTBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)\n{\n   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);\n}\n\nSTBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)\n{\n   int ix0,iy0;\n   stbtt_vertex *vertices;\n   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);\n   stbtt__bitmap gbm;\n\n   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);\n   gbm.pixels = output;\n   gbm.w = out_w;\n   gbm.h = out_h;\n   gbm.stride = out_stride;\n\n   if (gbm.w && gbm.h)\n      stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);\n\n   STBTT_free(vertices, info->userdata);\n}\n\nSTBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)\n{\n   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);\n}\n\nSTBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)\n{\n   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);\n}\n\nSTBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)\n{\n   stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));\n}\n\nSTBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)\n{\n   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));\n}\n\nSTBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)\n{\n   return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);\n}\n\nSTBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)\n{\n   stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);\n}\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  bitmap baking */\n/*  */\n/*  This is SUPER-CRAPPY packing to keep source code small */\n\nstatic int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset,  /*  font location (use offset=0 for plain .ttf) */\n                                float pixel_height,                     /*  height of font in pixels */\n                                unsigned char *pixels, int pw, int ph,  /*  bitmap to be filled in */\n                                int first_char, int num_chars,          /*  characters to bake */\n                                stbtt_bakedchar *chardata)\n{\n   float scale;\n   int x,y,bottom_y, i;\n   stbtt_fontinfo f;\n   f.userdata = NULL;\n   if (!stbtt_InitFont(&f, data, offset))\n      return -1;\n   STBTT_memset(pixels, 0, pw*ph); /*  background of 0 around pixels */\n   x=y=1;\n   bottom_y = 1;\n\n   scale = stbtt_ScaleForPixelHeight(&f, pixel_height);\n\n   for (i=0; i < num_chars; ++i) {\n      int advance, lsb, x0,y0,x1,y1,gw,gh;\n      int g = stbtt_FindGlyphIndex(&f, first_char + i);\n      stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);\n      stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);\n      gw = x1-x0;\n      gh = y1-y0;\n      if (x + gw + 1 >= pw)\n         y = bottom_y, x = 1; /*  advance to next row */\n      if (y + gh + 1 >= ph) /*  check if it fits vertically AFTER potentially moving to next row */\n         return -i;\n      STBTT_assert(x+gw < pw);\n      STBTT_assert(y+gh < ph);\n      stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);\n      chardata[i].x0 = (stbtt_int16) x;\n      chardata[i].y0 = (stbtt_int16) y;\n      chardata[i].x1 = (stbtt_int16) (x + gw);\n      chardata[i].y1 = (stbtt_int16) (y + gh);\n      chardata[i].xadvance = scale * advance;\n      chardata[i].xoff     = (float) x0;\n      chardata[i].yoff     = (float) y0;\n      x = x + gw + 1;\n      if (y+gh+1 > bottom_y)\n         bottom_y = y+gh+1;\n   }\n   return bottom_y;\n}\n\nSTBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)\n{\n   float d3d_bias = opengl_fillrule ? 0 : -0.5f;\n   float ipw = 1.0f / pw, iph = 1.0f / ph;\n   const stbtt_bakedchar *b = chardata + char_index;\n   int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);\n   int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);\n\n   q->x0 = round_x + d3d_bias;\n   q->y0 = round_y + d3d_bias;\n   q->x1 = round_x + b->x1 - b->x0 + d3d_bias;\n   q->y1 = round_y + b->y1 - b->y0 + d3d_bias;\n\n   q->s0 = b->x0 * ipw;\n   q->t0 = b->y0 * iph;\n   q->s1 = b->x1 * ipw;\n   q->t1 = b->y1 * iph;\n\n   *xpos += b->xadvance;\n}\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  rectangle packing replacement routines if you don't have stb_rect_pack.h */\n/*  */\n\n#ifndef STB_RECT_PACK_VERSION\n\ntypedef int stbrp_coord;\n\n/* ////////////////////////////////////////////////////////////////////////////////// */\n/*                                                                                 // */\n/*                                                                                 // */\n/*  COMPILER WARNING ?!?!?                                                         // */\n/*                                                                                 // */\n/*                                                                                 // */\n/*  if you get a compile warning due to these symbols being defined more than      // */\n/*  once, move #include \"stb_rect_pack.h\" before #include \"stb_truetype.h\"         // */\n/*                                                                                 // */\n/* ////////////////////////////////////////////////////////////////////////////////// */\n\ntypedef struct\n{\n   int width,height;\n   int x,y,bottom_y;\n} stbrp_context;\n\ntypedef struct\n{\n   unsigned char x;\n} stbrp_node;\n\nstruct stbrp_rect\n{\n   stbrp_coord x,y;\n   int id,w,h,was_packed;\n};\n\nstatic void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)\n{\n   con->width  = pw;\n   con->height = ph;\n   con->x = 0;\n   con->y = 0;\n   con->bottom_y = 0;\n   STBTT__NOTUSED(nodes);\n   STBTT__NOTUSED(num_nodes);\n}\n\nstatic void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)\n{\n   int i;\n   for (i=0; i < num_rects; ++i) {\n      if (con->x + rects[i].w > con->width) {\n         con->x = 0;\n         con->y = con->bottom_y;\n      }\n      if (con->y + rects[i].h > con->height)\n         break;\n      rects[i].x = con->x;\n      rects[i].y = con->y;\n      rects[i].was_packed = 1;\n      con->x += rects[i].w;\n      if (con->y + rects[i].h > con->bottom_y)\n         con->bottom_y = con->y + rects[i].h;\n   }\n   for (   ; i < num_rects; ++i)\n      rects[i].was_packed = 0;\n}\n#endif\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  bitmap baking */\n/*  */\n/*  This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If */\n/*  stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy. */\n\nSTBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)\n{\n   stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context)            ,alloc_context);\n   int            num_nodes = pw - padding;\n   stbrp_node    *nodes   = (stbrp_node    *) STBTT_malloc(sizeof(*nodes  ) * num_nodes,alloc_context);\n\n   if (context == NULL || nodes == NULL) {\n      if (context != NULL) STBTT_free(context, alloc_context);\n      if (nodes   != NULL) STBTT_free(nodes  , alloc_context);\n      return 0;\n   }\n\n   spc->user_allocator_context = alloc_context;\n   spc->width = pw;\n   spc->height = ph;\n   spc->pixels = pixels;\n   spc->pack_info = context;\n   spc->nodes = nodes;\n   spc->padding = padding;\n   spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;\n   spc->h_oversample = 1;\n   spc->v_oversample = 1;\n   spc->skip_missing = 0;\n\n   stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);\n\n   if (pixels)\n      STBTT_memset(pixels, 0, pw*ph); /*  background of 0 around pixels */\n\n   return 1;\n}\n\nSTBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc)\n{\n   STBTT_free(spc->nodes    , spc->user_allocator_context);\n   STBTT_free(spc->pack_info, spc->user_allocator_context);\n}\n\nSTBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample)\n{\n   STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE);\n   STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE);\n   if (h_oversample <= STBTT_MAX_OVERSAMPLE)\n      spc->h_oversample = h_oversample;\n   if (v_oversample <= STBTT_MAX_OVERSAMPLE)\n      spc->v_oversample = v_oversample;\n}\n\nSTBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip)\n{\n   spc->skip_missing = skip;\n}\n\n#define STBTT__OVER_MASK  (STBTT_MAX_OVERSAMPLE-1)\n\nstatic void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)\n{\n   unsigned char buffer[STBTT_MAX_OVERSAMPLE];\n   int safe_w = w - kernel_width;\n   int j;\n   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); /*  suppress bogus warning from VS2013 -analyze */\n   for (j=0; j < h; ++j) {\n      int i;\n      unsigned int total;\n      STBTT_memset(buffer, 0, kernel_width);\n\n      total = 0;\n\n      /*  make kernel_width a constant in common cases so compiler can optimize out the divide */\n      switch (kernel_width) {\n         case 2:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / 2);\n            }\n            break;\n         case 3:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / 3);\n            }\n            break;\n         case 4:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / 4);\n            }\n            break;\n         case 5:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / 5);\n            }\n            break;\n         default:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / kernel_width);\n            }\n            break;\n      }\n\n      for (; i < w; ++i) {\n         STBTT_assert(pixels[i] == 0);\n         total -= buffer[i & STBTT__OVER_MASK];\n         pixels[i] = (unsigned char) (total / kernel_width);\n      }\n\n      pixels += stride_in_bytes;\n   }\n}\n\nstatic void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)\n{\n   unsigned char buffer[STBTT_MAX_OVERSAMPLE];\n   int safe_h = h - kernel_width;\n   int j;\n   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); /*  suppress bogus warning from VS2013 -analyze */\n   for (j=0; j < w; ++j) {\n      int i;\n      unsigned int total;\n      STBTT_memset(buffer, 0, kernel_width);\n\n      total = 0;\n\n      /*  make kernel_width a constant in common cases so compiler can optimize out the divide */\n      switch (kernel_width) {\n         case 2:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / 2);\n            }\n            break;\n         case 3:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / 3);\n            }\n            break;\n         case 4:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / 4);\n            }\n            break;\n         case 5:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / 5);\n            }\n            break;\n         default:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);\n            }\n            break;\n      }\n\n      for (; i < h; ++i) {\n         STBTT_assert(pixels[i*stride_in_bytes] == 0);\n         total -= buffer[i & STBTT__OVER_MASK];\n         pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);\n      }\n\n      pixels += 1;\n   }\n}\n\nstatic float stbtt__oversample_shift(int oversample)\n{\n   if (!oversample)\n      return 0.0f;\n\n   /*  The prefilter is a box filter of width \"oversample\", */\n   /*  which shifts phase by (oversample - 1)/2 pixels in */\n   /*  oversampled space. We want to shift in the opposite */\n   /*  direction to counter this. */\n   return (float)-(oversample - 1) / (2.0f * (float)oversample);\n}\n\n/*  rects array must be big enough to accommodate all characters in the given ranges */\nSTBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)\n{\n   int i,j,k;\n   int missing_glyph_added = 0;\n\n   k=0;\n   for (i=0; i < num_ranges; ++i) {\n      float fh = ranges[i].font_size;\n      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);\n      ranges[i].h_oversample = (unsigned char) spc->h_oversample;\n      ranges[i].v_oversample = (unsigned char) spc->v_oversample;\n      for (j=0; j < ranges[i].num_chars; ++j) {\n         int x0,y0,x1,y1;\n         int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];\n         int glyph = stbtt_FindGlyphIndex(info, codepoint);\n         if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) {\n            rects[k].w = rects[k].h = 0;\n         } else {\n            stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,\n                                            scale * spc->h_oversample,\n                                            scale * spc->v_oversample,\n                                            0,0,\n                                            &x0,&y0,&x1,&y1);\n            rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);\n            rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);\n            if (glyph == 0)\n               missing_glyph_added = 1;\n         }\n         ++k;\n      }\n   }\n\n   return k;\n}\n\nSTBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)\n{\n   stbtt_MakeGlyphBitmapSubpixel(info,\n                                 output,\n                                 out_w - (prefilter_x - 1),\n                                 out_h - (prefilter_y - 1),\n                                 out_stride,\n                                 scale_x,\n                                 scale_y,\n                                 shift_x,\n                                 shift_y,\n                                 glyph);\n\n   if (prefilter_x > 1)\n      stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);\n\n   if (prefilter_y > 1)\n      stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);\n\n   *sub_x = stbtt__oversample_shift(prefilter_x);\n   *sub_y = stbtt__oversample_shift(prefilter_y);\n}\n\n/*  rects array must be big enough to accommodate all characters in the given ranges */\nSTBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)\n{\n   int i,j,k, missing_glyph = -1, return_value = 1;\n\n   /*  save current values */\n   int old_h_over = spc->h_oversample;\n   int old_v_over = spc->v_oversample;\n\n   k = 0;\n   for (i=0; i < num_ranges; ++i) {\n      float fh = ranges[i].font_size;\n      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);\n      float recip_h,recip_v,sub_x,sub_y;\n      spc->h_oversample = ranges[i].h_oversample;\n      spc->v_oversample = ranges[i].v_oversample;\n      recip_h = 1.0f / spc->h_oversample;\n      recip_v = 1.0f / spc->v_oversample;\n      sub_x = stbtt__oversample_shift(spc->h_oversample);\n      sub_y = stbtt__oversample_shift(spc->v_oversample);\n      for (j=0; j < ranges[i].num_chars; ++j) {\n         stbrp_rect *r = &rects[k];\n         if (r->was_packed && r->w != 0 && r->h != 0) {\n            stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];\n            int advance, lsb, x0,y0,x1,y1;\n            int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];\n            int glyph = stbtt_FindGlyphIndex(info, codepoint);\n            stbrp_coord pad = (stbrp_coord) spc->padding;\n\n            /*  pad on left and top */\n            r->x += pad;\n            r->y += pad;\n            r->w -= pad;\n            r->h -= pad;\n            stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);\n            stbtt_GetGlyphBitmapBox(info, glyph,\n                                    scale * spc->h_oversample,\n                                    scale * spc->v_oversample,\n                                    &x0,&y0,&x1,&y1);\n            stbtt_MakeGlyphBitmapSubpixel(info,\n                                          spc->pixels + r->x + r->y*spc->stride_in_bytes,\n                                          r->w - spc->h_oversample+1,\n                                          r->h - spc->v_oversample+1,\n                                          spc->stride_in_bytes,\n                                          scale * spc->h_oversample,\n                                          scale * spc->v_oversample,\n                                          0,0,\n                                          glyph);\n\n            if (spc->h_oversample > 1)\n               stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,\n                                  r->w, r->h, spc->stride_in_bytes,\n                                  spc->h_oversample);\n\n            if (spc->v_oversample > 1)\n               stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,\n                                  r->w, r->h, spc->stride_in_bytes,\n                                  spc->v_oversample);\n\n            bc->x0       = (stbtt_int16)  r->x;\n            bc->y0       = (stbtt_int16)  r->y;\n            bc->x1       = (stbtt_int16) (r->x + r->w);\n            bc->y1       = (stbtt_int16) (r->y + r->h);\n            bc->xadvance =                scale * advance;\n            bc->xoff     =       (float)  x0 * recip_h + sub_x;\n            bc->yoff     =       (float)  y0 * recip_v + sub_y;\n            bc->xoff2    =                (x0 + r->w) * recip_h + sub_x;\n            bc->yoff2    =                (y0 + r->h) * recip_v + sub_y;\n\n            if (glyph == 0)\n               missing_glyph = j;\n         } else if (spc->skip_missing) {\n            return_value = 0;\n         } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) {\n            ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph];\n         } else {\n            return_value = 0; /*  if any fail, report failure */\n         }\n\n         ++k;\n      }\n   }\n\n   /*  restore original values */\n   spc->h_oversample = old_h_over;\n   spc->v_oversample = old_v_over;\n\n   return return_value;\n}\n\nSTBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)\n{\n   stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);\n}\n\nSTBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)\n{\n   stbtt_fontinfo info;\n   int i,j,n, return_value = 1;\n   /* stbrp_context *context = (stbrp_context *) spc->pack_info; */\n   stbrp_rect    *rects;\n\n   /*  flag all characters as NOT packed */\n   for (i=0; i < num_ranges; ++i)\n      for (j=0; j < ranges[i].num_chars; ++j)\n         ranges[i].chardata_for_range[j].x0 =\n         ranges[i].chardata_for_range[j].y0 =\n         ranges[i].chardata_for_range[j].x1 =\n         ranges[i].chardata_for_range[j].y1 = 0;\n\n   n = 0;\n   for (i=0; i < num_ranges; ++i)\n      n += ranges[i].num_chars;\n\n   rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);\n   if (rects == NULL)\n      return 0;\n\n   info.userdata = spc->user_allocator_context;\n   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));\n\n   n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);\n\n   stbtt_PackFontRangesPackRects(spc, rects, n);\n\n   return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);\n\n   STBTT_free(rects, spc->user_allocator_context);\n   return return_value;\n}\n\nSTBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,\n            int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)\n{\n   stbtt_pack_range range;\n   range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;\n   range.array_of_unicode_codepoints = NULL;\n   range.num_chars                   = num_chars_in_range;\n   range.chardata_for_range          = chardata_for_range;\n   range.font_size                   = font_size;\n   return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);\n}\n\nSTBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap)\n{\n   int i_ascent, i_descent, i_lineGap;\n   float scale;\n   stbtt_fontinfo info;\n   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));\n   scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);\n   stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);\n   *ascent  = (float) i_ascent  * scale;\n   *descent = (float) i_descent * scale;\n   *lineGap = (float) i_lineGap * scale;\n}\n\nSTBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)\n{\n   float ipw = 1.0f / pw, iph = 1.0f / ph;\n   const stbtt_packedchar *b = chardata + char_index;\n\n   if (align_to_integer) {\n      float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);\n      float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);\n      q->x0 = x;\n      q->y0 = y;\n      q->x1 = x + b->xoff2 - b->xoff;\n      q->y1 = y + b->yoff2 - b->yoff;\n   } else {\n      q->x0 = *xpos + b->xoff;\n      q->y0 = *ypos + b->yoff;\n      q->x1 = *xpos + b->xoff2;\n      q->y1 = *ypos + b->yoff2;\n   }\n\n   q->s0 = b->x0 * ipw;\n   q->t0 = b->y0 * iph;\n   q->s1 = b->x1 * ipw;\n   q->t1 = b->y1 * iph;\n\n   *xpos += b->xadvance;\n}\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  sdf computation */\n/*  */\n\n#define STBTT_min(a,b)  ((a) < (b) ? (a) : (b))\n#define STBTT_max(a,b)  ((a) < (b) ? (b) : (a))\n\nstatic int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])\n{\n   float q0perp = q0[1]*ray[0] - q0[0]*ray[1];\n   float q1perp = q1[1]*ray[0] - q1[0]*ray[1];\n   float q2perp = q2[1]*ray[0] - q2[0]*ray[1];\n   float roperp = orig[1]*ray[0] - orig[0]*ray[1];\n\n   float a = q0perp - 2*q1perp + q2perp;\n   float b = q1perp - q0perp;\n   float c = q0perp - roperp;\n\n   float s0 = 0., s1 = 0.;\n   int num_s = 0;\n\n   if (a != 0.0) {\n      float discr = b*b - a*c;\n      if (discr > 0.0) {\n         float rcpna = -1 / a;\n         float d = (float) STBTT_sqrt(discr);\n         s0 = (b+d) * rcpna;\n         s1 = (b-d) * rcpna;\n         if (s0 >= 0.0 && s0 <= 1.0)\n            num_s = 1;\n         if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {\n            if (num_s == 0) s0 = s1;\n            ++num_s;\n         }\n      }\n   } else {\n      /*  2*b*s + c = 0 */\n      /*  s = -c / (2*b) */\n      s0 = c / (-2 * b);\n      if (s0 >= 0.0 && s0 <= 1.0)\n         num_s = 1;\n   }\n\n   if (num_s == 0)\n      return 0;\n   else {\n      float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);\n      float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;\n\n      float q0d =   q0[0]*rayn_x +   q0[1]*rayn_y;\n      float q1d =   q1[0]*rayn_x +   q1[1]*rayn_y;\n      float q2d =   q2[0]*rayn_x +   q2[1]*rayn_y;\n      float rod = orig[0]*rayn_x + orig[1]*rayn_y;\n\n      float q10d = q1d - q0d;\n      float q20d = q2d - q0d;\n      float q0rd = q0d - rod;\n\n      hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;\n      hits[0][1] = a*s0+b;\n\n      if (num_s > 1) {\n         hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;\n         hits[1][1] = a*s1+b;\n         return 2;\n      } else {\n         return 1;\n      }\n   }\n}\n\nstatic int stbtt__equal(float *a, float *b)\n{\n   return (a[0] == b[0] && a[1] == b[1]);\n}\n\nstatic int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)\n{\n   int i;\n   float orig[2], ray[2] = { 1, 0 };\n   float y_frac;\n   int winding = 0;\n\n   /*  make sure y never passes through a vertex of the shape */\n   y_frac = (float) STBTT_fmod(y, 1.0f);\n   if (y_frac < 0.01f)\n      y += 0.01f;\n   else if (y_frac > 0.99f)\n      y -= 0.01f;\n\n   orig[0] = x;\n   orig[1] = y;\n\n   /*  test a ray from (-infinity,y) to (x,y) */\n   for (i=0; i < nverts; ++i) {\n      if (verts[i].type == STBTT_vline) {\n         int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;\n         int x1 = (int) verts[i  ].x, y1 = (int) verts[i  ].y;\n         if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {\n            float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;\n            if (x_inter < x)\n               winding += (y0 < y1) ? 1 : -1;\n         }\n      }\n      if (verts[i].type == STBTT_vcurve) {\n         int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;\n         int x1 = (int) verts[i  ].cx, y1 = (int) verts[i  ].cy;\n         int x2 = (int) verts[i  ].x , y2 = (int) verts[i  ].y ;\n         int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));\n         int by = STBTT_max(y0,STBTT_max(y1,y2));\n         if (y > ay && y < by && x > ax) {\n            float q0[2],q1[2],q2[2];\n            float hits[2][2];\n            q0[0] = (float)x0;\n            q0[1] = (float)y0;\n            q1[0] = (float)x1;\n            q1[1] = (float)y1;\n            q2[0] = (float)x2;\n            q2[1] = (float)y2;\n            if (stbtt__equal(q0,q1) || stbtt__equal(q1,q2)) {\n               x0 = (int)verts[i-1].x;\n               y0 = (int)verts[i-1].y;\n               x1 = (int)verts[i  ].x;\n               y1 = (int)verts[i  ].y;\n               if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {\n                  float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;\n                  if (x_inter < x)\n                     winding += (y0 < y1) ? 1 : -1;\n               }\n            } else {\n               int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);\n               if (num_hits >= 1)\n                  if (hits[0][0] < 0)\n                     winding += (hits[0][1] < 0 ? -1 : 1);\n               if (num_hits >= 2)\n                  if (hits[1][0] < 0)\n                     winding += (hits[1][1] < 0 ? -1 : 1);\n            }\n         }\n      }\n   }\n   return winding;\n}\n\nstatic float stbtt__cuberoot( float x )\n{\n   if (x<0)\n      return -(float) STBTT_pow(-x,1.0f/3.0f);\n   else\n      return  (float) STBTT_pow( x,1.0f/3.0f);\n}\n\n/*  x^3 + a*x^2 + b*x + c = 0 */\nstatic int stbtt__solve_cubic(float a, float b, float c, float* r)\n{\n   float s = -a / 3;\n   float p = b - a*a / 3;\n   float q = a * (2*a*a - 9*b) / 27 + c;\n   float p3 = p*p*p;\n   float d = q*q + 4*p3 / 27;\n   if (d >= 0) {\n      float z = (float) STBTT_sqrt(d);\n      float u = (-q + z) / 2;\n      float v = (-q - z) / 2;\n      u = stbtt__cuberoot(u);\n      v = stbtt__cuberoot(v);\n      r[0] = s + u + v;\n      return 1;\n   } else {\n      float u = (float) STBTT_sqrt(-p/3);\n      float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; /*  p3 must be negative, since d is negative */\n      float m = (float) STBTT_cos(v);\n      float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;\n      r[0] = s + u * 2 * m;\n      r[1] = s - u * (m + n);\n      r[2] = s - u * (m - n);\n\n      /* STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f);  // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe? */\n      /* STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f); */\n      /* STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f); */\n      return 3;\n   }\n}\n\nSTBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)\n{\n   float scale_x = scale, scale_y = scale;\n   int ix0,iy0,ix1,iy1;\n   int w,h;\n   unsigned char *data;\n\n   if (scale == 0) return NULL;\n\n   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);\n\n   /*  if empty, return NULL */\n   if (ix0 == ix1 || iy0 == iy1)\n      return NULL;\n\n   ix0 -= padding;\n   iy0 -= padding;\n   ix1 += padding;\n   iy1 += padding;\n\n   w = (ix1 - ix0);\n   h = (iy1 - iy0);\n\n   if (width ) *width  = w;\n   if (height) *height = h;\n   if (xoff  ) *xoff   = ix0;\n   if (yoff  ) *yoff   = iy0;\n\n   /*  invert for y-downwards bitmaps */\n   scale_y = -scale_y;\n\n   {\n      int x,y,i,j;\n      float *precompute;\n      stbtt_vertex *verts;\n      int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);\n      data = (unsigned char *) STBTT_malloc(w * h, info->userdata);\n      precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);\n\n      for (i=0,j=num_verts-1; i < num_verts; j=i++) {\n         if (verts[i].type == STBTT_vline) {\n            float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;\n            float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;\n            float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));\n            precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;\n         } else if (verts[i].type == STBTT_vcurve) {\n            float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;\n            float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;\n            float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;\n            float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;\n            float len2 = bx*bx + by*by;\n            if (len2 != 0.0f)\n               precompute[i] = 1.0f / (bx*bx + by*by);\n            else\n               precompute[i] = 0.0f;\n         } else\n            precompute[i] = 0.0f;\n      }\n\n      for (y=iy0; y < iy1; ++y) {\n         for (x=ix0; x < ix1; ++x) {\n            float val;\n            float min_dist = 999999.0f;\n            float sx = (float) x + 0.5f;\n            float sy = (float) y + 0.5f;\n            float x_gspace = (sx / scale_x);\n            float y_gspace = (sy / scale_y);\n\n            int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); /*  @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path */\n\n            for (i=0; i < num_verts; ++i) {\n               float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;\n\n               if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {\n                  float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;\n\n                  float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);\n                  if (dist2 < min_dist*min_dist)\n                     min_dist = (float) STBTT_sqrt(dist2);\n\n                  /*  coarse culling against bbox */\n                  /* if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist && */\n                  /*     sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist) */\n                  dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];\n                  STBTT_assert(i != 0);\n                  if (dist < min_dist) {\n                     /*  check position along line */\n                     /*  x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0) */\n                     /*  minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy) */\n                     float dx = x1-x0, dy = y1-y0;\n                     float px = x0-sx, py = y0-sy;\n                     /*  minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy */\n                     /*  derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve */\n                     float t = -(px*dx + py*dy) / (dx*dx + dy*dy);\n                     if (t >= 0.0f && t <= 1.0f)\n                        min_dist = dist;\n                  }\n               } else if (verts[i].type == STBTT_vcurve) {\n                  float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;\n                  float x1 = verts[i  ].cx*scale_x, y1 = verts[i  ].cy*scale_y;\n                  float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);\n                  float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);\n                  float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);\n                  float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);\n                  /*  coarse culling against bbox to avoid computing cubic unnecessarily */\n                  if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {\n                     int num=0;\n                     float ax = x1-x0, ay = y1-y0;\n                     float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;\n                     float mx = x0 - sx, my = y0 - sy;\n                     float res[3] = {0.f,0.f,0.f};\n                     float px,py,t,it,dist2;\n                     float a_inv = precompute[i];\n                     if (a_inv == 0.0) { /*  if a_inv is 0, it's 2nd degree so use quadratic formula */\n                        float a = 3*(ax*bx + ay*by);\n                        float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);\n                        float c = mx*ax+my*ay;\n                        if (a == 0.0) { /*  if a is 0, it's linear */\n                           if (b != 0.0) {\n                              res[num++] = -c/b;\n                           }\n                        } else {\n                           float discriminant = b*b - 4*a*c;\n                           if (discriminant < 0)\n                              num = 0;\n                           else {\n                              float root = (float) STBTT_sqrt(discriminant);\n                              res[0] = (-b - root)/(2*a);\n                              res[1] = (-b + root)/(2*a);\n                              num = 2; /*  don't bother distinguishing 1-solution case, as code below will still work */\n                           }\n                        }\n                     } else {\n                        float b = 3*(ax*bx + ay*by) * a_inv; /*  could precompute this as it doesn't depend on sample point */\n                        float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;\n                        float d = (mx*ax+my*ay) * a_inv;\n                        num = stbtt__solve_cubic(b, c, d, res);\n                     }\n                     dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);\n                     if (dist2 < min_dist*min_dist)\n                        min_dist = (float) STBTT_sqrt(dist2);\n\n                     if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {\n                        t = res[0], it = 1.0f - t;\n                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;\n                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;\n                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);\n                        if (dist2 < min_dist * min_dist)\n                           min_dist = (float) STBTT_sqrt(dist2);\n                     }\n                     if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {\n                        t = res[1], it = 1.0f - t;\n                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;\n                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;\n                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);\n                        if (dist2 < min_dist * min_dist)\n                           min_dist = (float) STBTT_sqrt(dist2);\n                     }\n                     if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {\n                        t = res[2], it = 1.0f - t;\n                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;\n                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;\n                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);\n                        if (dist2 < min_dist * min_dist)\n                           min_dist = (float) STBTT_sqrt(dist2);\n                     }\n                  }\n               }\n            }\n            if (winding == 0)\n               min_dist = -min_dist;  /*  if outside the shape, value is negative */\n            val = onedge_value + pixel_dist_scale * min_dist;\n            if (val < 0)\n               val = 0;\n            else if (val > 255)\n               val = 255;\n            data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;\n         }\n      }\n      STBTT_free(precompute, info->userdata);\n      STBTT_free(verts, info->userdata);\n   }\n   return data;\n}\n\nSTBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)\n{\n   return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);\n}\n\nSTBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)\n{\n   STBTT_free(bitmap, userdata);\n}\n\n/* //////////////////////////////////////////////////////////////////////////// */\n/*  */\n/*  font name matching -- recommended not to use this */\n/*  */\n\n/*  check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string */\nstatic stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)\n{\n   stbtt_int32 i=0;\n\n   /*  convert utf16 to utf8 and compare the results while converting */\n   while (len2) {\n      stbtt_uint16 ch = s2[0]*256 + s2[1];\n      if (ch < 0x80) {\n         if (i >= len1) return -1;\n         if (s1[i++] != ch) return -1;\n      } else if (ch < 0x800) {\n         if (i+1 >= len1) return -1;\n         if (s1[i++] != 0xc0 + (ch >> 6)) return -1;\n         if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;\n      } else if (ch >= 0xd800 && ch < 0xdc00) {\n         stbtt_uint32 c;\n         stbtt_uint16 ch2 = s2[2]*256 + s2[3];\n         if (i+3 >= len1) return -1;\n         c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;\n         if (s1[i++] != 0xf0 + (c >> 18)) return -1;\n         if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;\n         if (s1[i++] != 0x80 + ((c >>  6) & 0x3f)) return -1;\n         if (s1[i++] != 0x80 + ((c      ) & 0x3f)) return -1;\n         s2 += 2; /*  plus another 2 below */\n         len2 -= 2;\n      } else if (ch >= 0xdc00 && ch < 0xe000) {\n         return -1;\n      } else {\n         if (i+2 >= len1) return -1;\n         if (s1[i++] != 0xe0 + (ch >> 12)) return -1;\n         if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;\n         if (s1[i++] != 0x80 + ((ch     ) & 0x3f)) return -1;\n      }\n      s2 += 2;\n      len2 -= 2;\n   }\n   return i;\n}\n\nstatic int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)\n{\n   return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);\n}\n\n/*  returns results in whatever encoding you request... but note that 2-byte encodings */\n/*  will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare */\nSTBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)\n{\n   stbtt_int32 i,count,stringOffset;\n   stbtt_uint8 *fc = font->data;\n   stbtt_uint32 offset = font->fontstart;\n   stbtt_uint32 nm = stbtt__find_table(fc, offset, \"name\");\n   if (!nm) return NULL;\n\n   count = ttUSHORT(fc+nm+2);\n   stringOffset = nm + ttUSHORT(fc+nm+4);\n   for (i=0; i < count; ++i) {\n      stbtt_uint32 loc = nm + 6 + 12 * i;\n      if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)\n          && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {\n         *length = ttUSHORT(fc+loc+8);\n         return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));\n      }\n   }\n   return NULL;\n}\n\nstatic int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)\n{\n   stbtt_int32 i;\n   stbtt_int32 count = ttUSHORT(fc+nm+2);\n   stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);\n\n   for (i=0; i < count; ++i) {\n      stbtt_uint32 loc = nm + 6 + 12 * i;\n      stbtt_int32 id = ttUSHORT(fc+loc+6);\n      if (id == target_id) {\n         /*  find the encoding */\n         stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);\n\n         /*  is this a Unicode encoding? */\n         if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {\n            stbtt_int32 slen = ttUSHORT(fc+loc+8);\n            stbtt_int32 off = ttUSHORT(fc+loc+10);\n\n            /*  check if there's a prefix match */\n            stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);\n            if (matchlen >= 0) {\n               /*  check for target_id+1 immediately following, with same encoding & language */\n               if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {\n                  slen = ttUSHORT(fc+loc+12+8);\n                  off = ttUSHORT(fc+loc+12+10);\n                  if (slen == 0) {\n                     if (matchlen == nlen)\n                        return 1;\n                  } else if (matchlen < nlen && name[matchlen] == ' ') {\n                     ++matchlen;\n                     if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))\n                        return 1;\n                  }\n               } else {\n                  /*  if nothing immediately following */\n                  if (matchlen == nlen)\n                     return 1;\n               }\n            }\n         }\n\n         /*  @TODO handle other encodings */\n      }\n   }\n   return 0;\n}\n\nstatic int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)\n{\n   stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);\n   stbtt_uint32 nm,hd;\n   if (!stbtt__isfont(fc+offset)) return 0;\n\n   /*  check italics/bold/underline flags in macStyle... */\n   if (flags) {\n      hd = stbtt__find_table(fc, offset, \"head\");\n      if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;\n   }\n\n   nm = stbtt__find_table(fc, offset, \"name\");\n   if (!nm) return 0;\n\n   if (flags) {\n      /*  if we checked the macStyle flags, then just check the family and ignore the subfamily */\n      if (stbtt__matchpair(fc, nm, name, nlen, 16, -1))  return 1;\n      if (stbtt__matchpair(fc, nm, name, nlen,  1, -1))  return 1;\n      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;\n   } else {\n      if (stbtt__matchpair(fc, nm, name, nlen, 16, 17))  return 1;\n      if (stbtt__matchpair(fc, nm, name, nlen,  1,  2))  return 1;\n      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;\n   }\n\n   return 0;\n}\n\nstatic int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags)\n{\n   stbtt_int32 i;\n   for (i=0;;++i) {\n      stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);\n      if (off < 0) return off;\n      if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))\n         return off;\n   }\n}\n\n#if defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wcast-qual\"\n#endif\n\nSTBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,\n                                float pixel_height, unsigned char *pixels, int pw, int ph,\n                                int first_char, int num_chars, stbtt_bakedchar *chardata)\n{\n   return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);\n}\n\nSTBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)\n{\n   return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);\n}\n\nSTBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)\n{\n   return stbtt_GetNumberOfFonts_internal((unsigned char *) data);\n}\n\nSTBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)\n{\n   return stbtt_InitFont_internal(info, (unsigned char *) data, offset);\n}\n\nSTBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags)\n{\n   return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags);\n}\n\nSTBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)\n{\n   return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2);\n}\n\n#if defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic pop\n#endif\n\n#endif /*  STB_TRUETYPE_IMPLEMENTATION */\n\n\n/*  FULL VERSION HISTORY */\n/*  */\n/*    1.25 (2021-07-11) many fixes */\n/*    1.24 (2020-02-05) fix warning */\n/*    1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS) */\n/*    1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined */\n/*    1.21 (2019-02-25) fix warning */\n/*    1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics() */\n/*    1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod */\n/*    1.18 (2018-01-29) add missing function */\n/*    1.17 (2017-07-23) make more arguments const; doc fix */\n/*    1.16 (2017-07-12) SDF support */\n/*    1.15 (2017-03-03) make more arguments const */\n/*    1.14 (2017-01-16) num-fonts-in-TTC function */\n/*    1.13 (2017-01-02) support OpenType fonts, certain Apple fonts */\n/*    1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual */\n/*    1.11 (2016-04-02) fix unused-variable warning */\n/*    1.10 (2016-04-02) allow user-defined fabs() replacement */\n/*                      fix memory leak if fontsize=0.0 */\n/*                      fix warning from duplicate typedef */\n/*    1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges */\n/*    1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges */\n/*    1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints; */\n/*                      allow PackFontRanges to pack and render in separate phases; */\n/*                      fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?); */\n/*                      fixed an assert() bug in the new rasterizer */\n/*                      replace assert() with STBTT_assert() in new rasterizer */\n/*    1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine) */\n/*                      also more precise AA rasterizer, except if shapes overlap */\n/*                      remove need for STBTT_sort */\n/*    1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC */\n/*    1.04 (2015-04-15) typo in example */\n/*    1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes */\n/*    1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++ */\n/*    1.01 (2014-12-08) fix subpixel position when oversampling to exactly match */\n/*                         non-oversampled; STBTT_POINT_SIZE for packed case only */\n/*    1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling */\n/*    0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg) */\n/*    0.9  (2014-08-07) support certain mac/iOS fonts without an MS platformID */\n/*    0.8b (2014-07-07) fix a warning */\n/*    0.8  (2014-05-25) fix a few more warnings */\n/*    0.7  (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back */\n/*    0.6c (2012-07-24) improve documentation */\n/*    0.6b (2012-07-20) fix a few more warnings */\n/*    0.6  (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels, */\n/*                         stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty */\n/*    0.5  (2011-12-09) bugfixes: */\n/*                         subpixel glyph renderer computed wrong bounding box */\n/*                         first vertex of shape can be off-curve (FreeSans) */\n/*    0.4b (2011-12-03) fixed an error in the font baking example */\n/*    0.4  (2011-12-01) kerning, subpixel rendering (tor) */\n/*                     bugfixes for: */\n/*                         codepoint-to-glyph conversion using table fmt=12 */\n/*                         codepoint-to-glyph conversion using table fmt=4 */\n/*                         stbtt_GetBakedQuad with non-square texture (Zer) */\n/*                     updated Hello World! sample to use kerning and subpixel */\n/*                     fixed some warnings */\n/*    0.3  (2009-06-24) cmap fmt=12, compound shapes (MM) */\n/*                     userdata, malloc-from-userdata, non-zero fill (stb) */\n/*    0.2  (2009-03-11) Fix unsigned/signed char warnings */\n/*    0.1  (2009-03-09) First public release */\n/*  */\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n\n\n\n\n#ifdef NK_INCLUDE_FONT_BAKING\n/* -------------------------------------------------------------\n *\n *                          RECT PACK\n *\n * --------------------------------------------------------------*/\n\n\n\n/*\n * ==============================================================\n *\n *                          TRUETYPE\n *\n * ===============================================================\n */\n#define STBTT_MAX_OVERSAMPLE   8\n\n\n/* -------------------------------------------------------------\n *\n *                          FONT BAKING\n *\n * --------------------------------------------------------------*/\nstruct nk_font_bake_data {\n    struct stbtt_fontinfo info;\n    struct stbrp_rect *rects;\n    stbtt_pack_range *ranges;\n    nk_rune range_count;\n};\n\nstruct nk_font_baker {\n    struct nk_allocator alloc;\n    struct stbtt_pack_context spc;\n    struct nk_font_bake_data *build;\n    stbtt_packedchar *packed_chars;\n    struct stbrp_rect *rects;\n    stbtt_pack_range *ranges;\n};\n\nNK_GLOBAL const nk_size nk_rect_align = NK_ALIGNOF(struct stbrp_rect);\nNK_GLOBAL const nk_size nk_range_align = NK_ALIGNOF(stbtt_pack_range);\nNK_GLOBAL const nk_size nk_char_align = NK_ALIGNOF(stbtt_packedchar);\nNK_GLOBAL const nk_size nk_build_align = NK_ALIGNOF(struct nk_font_bake_data);\nNK_GLOBAL const nk_size nk_baker_align = NK_ALIGNOF(struct nk_font_baker);\n\nNK_INTERN int\nnk_range_count(const nk_rune *range)\n{\n    const nk_rune *iter = range;\n    NK_ASSERT(range);\n    if (!range) return 0;\n    while (*(iter++) != 0);\n    return (iter == range) ? 0 : (int)((iter - range)/2);\n}\nNK_INTERN int\nnk_range_glyph_count(const nk_rune *range, int count)\n{\n    int i = 0;\n    int total_glyphs = 0;\n    for (i = 0; i < count; ++i) {\n        int diff;\n        nk_rune f = range[(i*2)+0];\n        nk_rune t = range[(i*2)+1];\n        NK_ASSERT(t >= f);\n        diff = (int)((t - f) + 1);\n        total_glyphs += diff;\n    }\n    return total_glyphs;\n}\nNK_API const nk_rune*\nnk_font_default_glyph_ranges(void)\n{\n    NK_STORAGE const nk_rune ranges[] = {0x0020, 0x00FF, 0};\n    return ranges;\n}\nNK_API const nk_rune*\nnk_font_chinese_glyph_ranges(void)\n{\n    NK_STORAGE const nk_rune ranges[] = {\n        0x0020, 0x00FF,\n        0x3000, 0x30FF,\n        0x31F0, 0x31FF,\n        0xFF00, 0xFFEF,\n        0x4E00, 0x9FAF,\n        0\n    };\n    return ranges;\n}\nNK_API const nk_rune*\nnk_font_cyrillic_glyph_ranges(void)\n{\n    NK_STORAGE const nk_rune ranges[] = {\n        0x0020, 0x00FF,\n        0x0400, 0x052F,\n        0x2DE0, 0x2DFF,\n        0xA640, 0xA69F,\n        0\n    };\n    return ranges;\n}\nNK_API const nk_rune*\nnk_font_korean_glyph_ranges(void)\n{\n    NK_STORAGE const nk_rune ranges[] = {\n        0x0020, 0x00FF,\n        0x3131, 0x3163,\n        0xAC00, 0xD79D,\n        0\n    };\n    return ranges;\n}\nNK_INTERN void\nnk_font_baker_memory(nk_size *temp, int *glyph_count,\n    struct nk_font_config *config_list, int count)\n{\n    int range_count = 0;\n    int total_range_count = 0;\n    struct nk_font_config *iter, *i;\n\n    NK_ASSERT(config_list);\n    NK_ASSERT(glyph_count);\n    if (!config_list) {\n        *temp = 0;\n        *glyph_count = 0;\n        return;\n    }\n    *glyph_count = 0;\n    for (iter = config_list; iter; iter = iter->next) {\n        i = iter;\n        do {if (!i->range) iter->range = nk_font_default_glyph_ranges();\n            range_count = nk_range_count(i->range);\n            total_range_count += range_count;\n            *glyph_count += nk_range_glyph_count(i->range, range_count);\n        } while ((i = i->n) != iter);\n    }\n    *temp = (nk_size)*glyph_count * sizeof(struct stbrp_rect);\n    *temp += (nk_size)total_range_count * sizeof(stbtt_pack_range);\n    *temp += (nk_size)*glyph_count * sizeof(stbtt_packedchar);\n    *temp += (nk_size)count * sizeof(struct nk_font_bake_data);\n    *temp += sizeof(struct nk_font_baker);\n    *temp += nk_rect_align + nk_range_align + nk_char_align;\n    *temp += nk_build_align + nk_baker_align;\n}\nNK_INTERN struct nk_font_baker*\nnk_font_baker(void *memory, int glyph_count, int count, const struct nk_allocator *alloc)\n{\n    struct nk_font_baker *baker;\n    if (!memory) return 0;\n    /* setup baker inside a memory block  */\n    baker = (struct nk_font_baker*)NK_ALIGN_PTR(memory, nk_baker_align);\n    baker->build = (struct nk_font_bake_data*)NK_ALIGN_PTR((baker + 1), nk_build_align);\n    baker->packed_chars = (stbtt_packedchar*)NK_ALIGN_PTR((baker->build + count), nk_char_align);\n    baker->rects = (struct stbrp_rect*)NK_ALIGN_PTR((baker->packed_chars + glyph_count), nk_rect_align);\n    baker->ranges = (stbtt_pack_range*)NK_ALIGN_PTR((baker->rects + glyph_count), nk_range_align);\n    baker->alloc = *alloc;\n    return baker;\n}\nNK_INTERN int\nnk_font_bake_pack(struct nk_font_baker *baker,\n    nk_size *image_memory, int *width, int *height, struct nk_recti *custom,\n    const struct nk_font_config *config_list, int count,\n    const struct nk_allocator *alloc)\n{\n    NK_STORAGE const nk_size max_height = 1024 * 32;\n    const struct nk_font_config *config_iter, *it;\n    int total_glyph_count = 0;\n    int total_range_count = 0;\n    int range_count = 0;\n    int i = 0;\n\n    NK_ASSERT(image_memory);\n    NK_ASSERT(width);\n    NK_ASSERT(height);\n    NK_ASSERT(config_list);\n    NK_ASSERT(count);\n    NK_ASSERT(alloc);\n\n    if (!image_memory || !width || !height || !config_list || !count) return nk_false;\n    for (config_iter = config_list; config_iter; config_iter = config_iter->next) {\n        it = config_iter;\n        do {range_count = nk_range_count(it->range);\n            total_range_count += range_count;\n            total_glyph_count += nk_range_glyph_count(it->range, range_count);\n        } while ((it = it->n) != config_iter);\n    }\n    /* setup font baker from temporary memory */\n    for (config_iter = config_list; config_iter; config_iter = config_iter->next) {\n        it = config_iter;\n        do {\n            struct stbtt_fontinfo *font_info = &baker->build[i++].info;\n            font_info->userdata = (void*)alloc;\n\n            if (!stbtt_InitFont(font_info, (const unsigned char*)it->ttf_blob, stbtt_GetFontOffsetForIndex((const unsigned char*)it->ttf_blob, 0)))\n                return nk_false;\n        } while ((it = it->n) != config_iter);\n    }\n    *height = 0;\n    *width = (total_glyph_count > 1000) ? 1024 : 512;\n    stbtt_PackBegin(&baker->spc, 0, (int)*width, (int)max_height, 0, 1, (void*)alloc);\n    {\n        int input_i = 0;\n        int range_n = 0;\n        int rect_n = 0;\n        int char_n = 0;\n\n        if (custom) {\n            /* pack custom user data first so it will be in the upper left corner*/\n            struct stbrp_rect custom_space;\n            nk_zero(&custom_space, sizeof(custom_space));\n            custom_space.w = (stbrp_coord)(custom->w);\n            custom_space.h = (stbrp_coord)(custom->h);\n\n            stbtt_PackSetOversampling(&baker->spc, 1, 1);\n            stbrp_pack_rects((struct stbrp_context*)baker->spc.pack_info, &custom_space, 1);\n            *height = NK_MAX(*height, (int)(custom_space.y + custom_space.h));\n\n            custom->x = (short)custom_space.x;\n            custom->y = (short)custom_space.y;\n            custom->w = (short)custom_space.w;\n            custom->h = (short)custom_space.h;\n        }\n\n        /* first font pass: pack all glyphs */\n        for (input_i = 0, config_iter = config_list; input_i < count && config_iter;\n            config_iter = config_iter->next) {\n            it = config_iter;\n            do {int n = 0;\n                int glyph_count;\n                const nk_rune *in_range;\n                const struct nk_font_config *cfg = it;\n                struct nk_font_bake_data *tmp = &baker->build[input_i++];\n\n                /* count glyphs + ranges in current font */\n                glyph_count = 0; range_count = 0;\n                for (in_range = cfg->range; in_range[0] && in_range[1]; in_range += 2) {\n                    glyph_count += (int)(in_range[1] - in_range[0]) + 1;\n                    range_count++;\n                }\n\n                /* setup ranges  */\n                tmp->ranges = baker->ranges + range_n;\n                tmp->range_count = (nk_rune)range_count;\n                range_n += range_count;\n                for (i = 0; i < range_count; ++i) {\n                    in_range = &cfg->range[i * 2];\n                    tmp->ranges[i].font_size = cfg->size;\n                    tmp->ranges[i].first_unicode_codepoint_in_range = (int)in_range[0];\n                    tmp->ranges[i].num_chars = (int)(in_range[1]- in_range[0]) + 1;\n                    tmp->ranges[i].chardata_for_range = baker->packed_chars + char_n;\n                    char_n += tmp->ranges[i].num_chars;\n                }\n\n                /* pack */\n                tmp->rects = baker->rects + rect_n;\n                rect_n += glyph_count;\n                stbtt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v);\n                n = stbtt_PackFontRangesGatherRects(&baker->spc, &tmp->info,\n                    tmp->ranges, (int)tmp->range_count, tmp->rects);\n                stbrp_pack_rects((struct stbrp_context*)baker->spc.pack_info, tmp->rects, (int)n);\n\n                /* texture height */\n                for (i = 0; i < n; ++i) {\n                    if (tmp->rects[i].was_packed)\n                        *height = NK_MAX(*height, tmp->rects[i].y + tmp->rects[i].h);\n                }\n            } while ((it = it->n) != config_iter);\n        }\n        NK_ASSERT(rect_n == total_glyph_count);\n        NK_ASSERT(char_n == total_glyph_count);\n        NK_ASSERT(range_n == total_range_count);\n    }\n    *height = (int)nk_round_up_pow2((nk_uint)*height);\n    *image_memory = (nk_size)(*width) * (nk_size)(*height);\n    return nk_true;\n}\nNK_INTERN void\nnk_font_bake(struct nk_font_baker *baker, void *image_memory, int width, int height,\n    struct nk_font_glyph *glyphs, int glyphs_count,\n    const struct nk_font_config *config_list, int font_count)\n{\n    int input_i = 0;\n    nk_rune glyph_n = 0;\n    const struct nk_font_config *config_iter;\n    const struct nk_font_config *it;\n\n    NK_ASSERT(image_memory);\n    NK_ASSERT(width);\n    NK_ASSERT(height);\n    NK_ASSERT(config_list);\n    NK_ASSERT(baker);\n    NK_ASSERT(font_count);\n    NK_ASSERT(glyphs_count);\n    if (!image_memory || !width || !height || !config_list ||\n        !font_count || !glyphs || !glyphs_count)\n        return;\n\n    /* second font pass: render glyphs */\n    nk_zero(image_memory, (nk_size)((nk_size)width * (nk_size)height));\n    baker->spc.pixels = (unsigned char*)image_memory;\n    baker->spc.height = (int)height;\n    for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter;\n        config_iter = config_iter->next) {\n        it = config_iter;\n        do {const struct nk_font_config *cfg = it;\n            struct nk_font_bake_data *tmp = &baker->build[input_i++];\n            stbtt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v);\n            stbtt_PackFontRangesRenderIntoRects(&baker->spc, &tmp->info, tmp->ranges, (int)tmp->range_count, tmp->rects);\n        } while ((it = it->n) != config_iter);\n    } stbtt_PackEnd(&baker->spc);\n\n    /* third pass: setup font and glyphs */\n    for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter;\n        config_iter = config_iter->next) {\n        it = config_iter;\n        do {nk_size i = 0;\n            int char_idx = 0;\n            nk_rune glyph_count = 0;\n            const struct nk_font_config *cfg = it;\n            struct nk_font_bake_data *tmp = &baker->build[input_i++];\n            struct nk_baked_font *dst_font = cfg->font;\n\n            float font_scale = stbtt_ScaleForPixelHeight(&tmp->info, cfg->size);\n            int unscaled_ascent, unscaled_descent, unscaled_line_gap;\n            stbtt_GetFontVMetrics(&tmp->info, &unscaled_ascent, &unscaled_descent,\n                                    &unscaled_line_gap);\n\n            /* fill baked font */\n            if (!cfg->merge_mode) {\n                dst_font->ranges = cfg->range;\n                dst_font->height = cfg->size;\n                dst_font->ascent = ((float)unscaled_ascent * font_scale);\n                dst_font->descent = ((float)unscaled_descent * font_scale);\n                dst_font->glyph_offset = glyph_n;\n                /*\n                    Need to zero this, or it will carry over from a previous\n                    bake, and cause a segfault when accessing glyphs[].\n                */\n                dst_font->glyph_count = 0;\n            }\n\n            /* fill own baked font glyph array */\n            for (i = 0; i < tmp->range_count; ++i) {\n                stbtt_pack_range *range = &tmp->ranges[i];\n                for (char_idx = 0; char_idx < range->num_chars; char_idx++)\n                {\n                    nk_rune codepoint = 0;\n                    float dummy_x = 0, dummy_y = 0;\n                    stbtt_aligned_quad q;\n                    struct nk_font_glyph *glyph;\n\n                    /* query glyph bounds from stb_truetype */\n                    const stbtt_packedchar *pc = &range->chardata_for_range[char_idx];\n                    codepoint = (nk_rune)(range->first_unicode_codepoint_in_range + char_idx);\n                    stbtt_GetPackedQuad(range->chardata_for_range, (int)width,\n                        (int)height, char_idx, &dummy_x, &dummy_y, &q, 0);\n\n                    /* fill own glyph type with data */\n                    glyph = &glyphs[dst_font->glyph_offset + dst_font->glyph_count + (unsigned int)glyph_count];\n                    glyph->codepoint = codepoint;\n                    glyph->x0 = q.x0; glyph->y0 = q.y0;\n                    glyph->x1 = q.x1; glyph->y1 = q.y1;\n                    glyph->y0 += (dst_font->ascent + 0.5f);\n                    glyph->y1 += (dst_font->ascent + 0.5f);\n                    glyph->w = glyph->x1 - glyph->x0 + 0.5f;\n                    glyph->h = glyph->y1 - glyph->y0;\n\n                    if (cfg->coord_type == NK_COORD_PIXEL) {\n                        glyph->u0 = q.s0 * (float)width;\n                        glyph->v0 = q.t0 * (float)height;\n                        glyph->u1 = q.s1 * (float)width;\n                        glyph->v1 = q.t1 * (float)height;\n                    } else {\n                        glyph->u0 = q.s0;\n                        glyph->v0 = q.t0;\n                        glyph->u1 = q.s1;\n                        glyph->v1 = q.t1;\n                    }\n                    glyph->xadvance = (pc->xadvance + cfg->spacing.x);\n                    if (cfg->pixel_snap)\n                        glyph->xadvance = (float)(int)(glyph->xadvance + 0.5f);\n                    glyph_count++;\n                }\n            }\n            dst_font->glyph_count += glyph_count;\n            glyph_n += glyph_count;\n        } while ((it = it->n) != config_iter);\n    }\n}\nNK_INTERN void\nnk_font_bake_custom_data(void *img_memory, int img_width, int img_height,\n    struct nk_recti img_dst, const char *texture_data_mask, int tex_width,\n    int tex_height, char white, char black)\n{\n    nk_byte *pixels;\n    int y = 0;\n    int x = 0;\n    int n = 0;\n\n    NK_ASSERT(img_memory);\n    NK_ASSERT(img_width);\n    NK_ASSERT(img_height);\n    NK_ASSERT(texture_data_mask);\n    NK_UNUSED(tex_height);\n    if (!img_memory || !img_width || !img_height || !texture_data_mask)\n        return;\n\n    pixels = (nk_byte*)img_memory;\n    for (y = 0, n = 0; y < tex_height; ++y) {\n        for (x = 0; x < tex_width; ++x, ++n) {\n            const int off0 = ((img_dst.x + x) + (img_dst.y + y) * img_width);\n            const int off1 = off0 + 1 + tex_width;\n            pixels[off0] = (texture_data_mask[n] == white) ? 0xFF : 0x00;\n            pixels[off1] = (texture_data_mask[n] == black) ? 0xFF : 0x00;\n        }\n    }\n}\nNK_INTERN void\nnk_font_bake_convert(void *out_memory, int img_width, int img_height,\n    const void *in_memory)\n{\n    int n = 0;\n    nk_rune *dst;\n    const nk_byte *src;\n\n    NK_ASSERT(out_memory);\n    NK_ASSERT(in_memory);\n    NK_ASSERT(img_width);\n    NK_ASSERT(img_height);\n    if (!out_memory || !in_memory || !img_height || !img_width) return;\n\n    dst = (nk_rune*)out_memory;\n    src = (const nk_byte*)in_memory;\n    for (n = (int)(img_width * img_height); n > 0; n--)\n        *dst++ = ((nk_rune)(*src++) << 24) | 0x00FFFFFF;\n}\n\n/* -------------------------------------------------------------\n *\n *                          FONT\n *\n * --------------------------------------------------------------*/\nNK_INTERN float\nnk_font_text_width(nk_handle handle, float height, const char *text, int len)\n{\n    nk_rune unicode;\n    int text_len  = 0;\n    float text_width = 0;\n    int glyph_len = 0;\n    float scale = 0;\n\n    struct nk_font *font = (struct nk_font*)handle.ptr;\n    NK_ASSERT(font);\n    NK_ASSERT(font->glyphs);\n    if (!font || !text || !len)\n        return 0;\n\n    scale = height/font->info.height;\n    glyph_len = text_len = nk_utf_decode(text, &unicode, (int)len);\n    if (!glyph_len) return 0;\n    while (text_len <= (int)len && glyph_len) {\n        const struct nk_font_glyph *g;\n        if (unicode == NK_UTF_INVALID) break;\n\n        /* query currently drawn glyph information */\n        g = nk_font_find_glyph(font, unicode);\n        text_width += g->xadvance * scale;\n\n        /* offset next glyph */\n        glyph_len = nk_utf_decode(text + text_len, &unicode, (int)len - text_len);\n        text_len += glyph_len;\n    }\n    return text_width;\n}\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\nNK_INTERN void\nnk_font_query_font_glyph(nk_handle handle, float height,\n    struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint)\n{\n    float scale;\n    const struct nk_font_glyph *g;\n    struct nk_font *font;\n\n    NK_ASSERT(glyph);\n    NK_UNUSED(next_codepoint);\n\n    font = (struct nk_font*)handle.ptr;\n    NK_ASSERT(font);\n    NK_ASSERT(font->glyphs);\n    if (!font || !glyph)\n        return;\n\n    scale = height/font->info.height;\n    g = nk_font_find_glyph(font, codepoint);\n    glyph->width = (g->x1 - g->x0) * scale;\n    glyph->height = (g->y1 - g->y0) * scale;\n    glyph->offset = nk_vec2(g->x0 * scale, g->y0 * scale);\n    glyph->xadvance = (g->xadvance * scale);\n    glyph->uv[0] = nk_vec2(g->u0, g->v0);\n    glyph->uv[1] = nk_vec2(g->u1, g->v1);\n}\n#endif\nNK_API const struct nk_font_glyph*\nnk_font_find_glyph(const struct nk_font *font, nk_rune unicode)\n{\n    int i = 0;\n    int count;\n    int total_glyphs = 0;\n    const struct nk_font_glyph *glyph = 0;\n    const struct nk_font_config *iter = 0;\n\n    NK_ASSERT(font);\n    NK_ASSERT(font->glyphs);\n    NK_ASSERT(font->info.ranges);\n    if (!font || !font->glyphs) return 0;\n\n    glyph = font->fallback;\n    iter = font->config;\n    do {count = nk_range_count(iter->range);\n        for (i = 0; i < count; ++i) {\n            nk_rune f = iter->range[(i*2)+0];\n            nk_rune t = iter->range[(i*2)+1];\n            int diff = (int)((t - f) + 1);\n            if (unicode >= f && unicode <= t)\n                return &font->glyphs[((nk_rune)total_glyphs + (unicode - f))];\n            total_glyphs += diff;\n        }\n    } while ((iter = iter->n) != font->config);\n    return glyph;\n}\nNK_INTERN void\nnk_font_init(struct nk_font *font, float pixel_height,\n    nk_rune fallback_codepoint, struct nk_font_glyph *glyphs,\n    const struct nk_baked_font *baked_font, nk_handle atlas)\n{\n    struct nk_baked_font baked;\n    NK_ASSERT(font);\n    NK_ASSERT(glyphs);\n    NK_ASSERT(baked_font);\n    if (!font || !glyphs || !baked_font)\n        return;\n\n    baked = *baked_font;\n    font->fallback = 0;\n    font->info = baked;\n    font->scale = (float)pixel_height / (float)font->info.height;\n    font->glyphs = &glyphs[baked_font->glyph_offset];\n    font->texture = atlas;\n    font->fallback_codepoint = fallback_codepoint;\n    font->fallback = nk_font_find_glyph(font, fallback_codepoint);\n\n    font->handle.height = font->info.height * font->scale;\n    font->handle.width = nk_font_text_width;\n    font->handle.userdata.ptr = font;\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n    font->handle.query = nk_font_query_font_glyph;\n    font->handle.texture = font->texture;\n#endif\n}\n\n/* ---------------------------------------------------------------------------\n *\n *                          DEFAULT FONT\n *\n * ProggyClean.ttf\n * Copyright (c) 2004, 2005 Tristan Grimmer\n * MIT license https://github.com/bluescan/proggyfonts/blob/master/LICENSE\n * Download and more information at https://github.com/bluescan/proggyfonts\n *-----------------------------------------------------------------------------*/\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Woverlength-strings\"\n#elif defined(__GNUC__) || defined(__GNUG__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Woverlength-strings\"\n#endif\n\n#ifdef NK_INCLUDE_DEFAULT_FONT\n\nNK_GLOBAL const char nk_proggy_clean_ttf_compressed_data_base85[11980+1] =\n    \"7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/\"\n    \"2*>]b(MC;$jPfY.;h^`IWM9<Lh2TlS+f-s$o6Q<BWH`YiU.xfLq$N;$0iR/GX:U(jcW2p/W*q?-qmnUCI;jHSAiFWM.R*kU@C=GH?a9wp8f$e.-4^Qg1)Q-GL(lf(r/7GrRgwV%MS=C#\"\n    \"`8ND>Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1<q-UE31#^-V'8IRUo7Qf./L>=Ke$$'5F%)]0^#0X@U.a<r:QLtFsLcL6##lOj)#.Y5<-R&KgLwqJfLgN&;Q?gI^#DY2uL\"\n    \"i@^rMl9t=cWq6##weg>$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;-<nLENhvx>-VsM.M0rJfLH2eTM`*oJMHRC`N\"\n    \"kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`&#0j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N\"\n    \"*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cX&#2m#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)\"\n    \"tm+/Us9pG)XPu`<0s-)WTt(gCRxIg(%6sfh=ktMKn3j)<6<b5Sk_/0(^]AaN#(p/L>&VZ>1i%h1S9u5o@YaaW$e+b<TWFn/Z:Oh(Cx2$lNEoN^e)#CFY@@I;BOQ*sRwZtZxRcU7uW6CX\"\n    \"ow0i(?$Q[cjOd[P4d)]>ROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc.\"\n    \"x]Ip.PH^'/aqUO/$1WxLoW0[iLA<QT;5HKD+@qQ'NQ(3_PLhE48R.qAPSwQ0/WK?Z,[x?-J;jQTWA0X@KJ(_Y8N-:/M74:/-ZpKrUss?d#dZq]DAbkU*JqkL+nwX@@47`5>w=4h(9.`G\"\n    \"CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?G<Nald$qs]@]L<J7bR*>gv:[7MI2k).'2($5FNP&EQ(,)\"\n    \"U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#\"\n    \"'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM\"\n    \"_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0<q-]L_?^)1vw'.,MRsqVr.L;aN&#/EgJ)PBc[-f>+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu\"\n    \"Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/\"\n    \"/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[K<L\"\n    \"%a2E-grWVM3@2=-k22tL]4$##6We'8UJCKE[d_=%wI;'6X-GsLX4j^SgJ$##R*w,vP3wK#iiW&#*h^D&R?jp7+/u&#(AP##XU8c$fSYW-J95_-Dp[g9wcO&#M-h1OcJlc-*vpw0xUX&#\"\n    \"OQFKNX@QI'IoPp7nb,QU//MQ&ZDkKP)X<WSVL(68uVl&#c'[0#(s1X&xm$Y%B7*K:eDA323j998GXbA#pwMs-jgD$9QISB-A_(aN4xoFM^@C58D0+Q+q3n0#3U1InDjF682-SjMXJK)(\"\n    \"h$hxua_K]ul92%'BOU&#BRRh-slg8KDlr:%L71Ka:.A;%YULjDPmL<LYs8i#XwJOYaKPKc1h:'9Ke,g)b),78=I39B;xiY$bgGw-&.Zi9InXDuYa%G*f2Bq7mn9^#p1vv%#(Wi-;/Z5h\"\n    \"o;#2:;%d&#x9v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO\"\n    \"j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J<j$UpK<Q4a1]MupW^-\"\n    \"sj_$%[HK%'F####QRZJ::Y3EGl4'@%FkiAOg#p[##O`gukTfBHagL<LHw%q&OV0##F=6/:chIm0@eCP8X]:kFI%hl8hgO@RcBhS-@Qb$%+m=hPDLg*%K8ln(wcf3/'DW-$.lR?n[nCH-\"\n    \"eXOONTJlh:.RYF%3'p6sq:UIMA945&^HFS87@$EP2iG<-lCO$%c`uKGD3rC$x0BL8aFn--`ke%#HMP'vh1/R&O_J9'um,.<tx[@%wsJk&bUT2`0uMv7gg#qp/ij.L56'hl;.s5CUrxjO\"\n    \"M7-##.l+Au'A&O:-T72L]P`&=;ctp'XScX*rU.>-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%\"\n    \"LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$M<Jnq79VsJW/mWS*PUiq76;]/NM_>hLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]\"\n    \"%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et\"\n    \"Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$<M-SGZ':+Q_k+uvOSLiEo(<aD/K<CCc`'Lx>'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:\"\n    \"a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VB<HFF*qL(\"\n    \"$/V,;(kXZejWO`<[5?\\?ewY(*9=%wDc;,u<'9t3W-(H1th3+G]ucQ]kLs7df($/*JL]@*t7Bu_G3_7mp7<iaQjO@.kLg;x3B0lqp7Hf,^Ze7-##@/c58Mo(3;knp0%)A7?-W+eI'o8)b<\"\n    \"nKnw'Ho8C=Y>pqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<<aG/1N$#FX$0V5Y6x'aErI3I$7x%E`v<-BY,)%-?Psf*l?%C3.mM(=/M0:JxG'?\"\n    \"7WhH%o'a<-80g0NBxoO(GH<dM]n.+%q@jH?f.UsJ2Ggs&4<-e47&Kl+f//9@`b+?.TeN_&B8Ss?v;^Trk;f#YvJkl&w$]>-+k?'(<S:68tq*WoDfZu';mM?8X[ma8W%*`-=;D.(nc7/;\"\n    \")g:T1=^J$&BRV(-lTmNB6xqB[@0*o.erM*<SWF]u2=st-*(6v>^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M\"\n    \"D?@f&1'BW-)Ju<L25gl8uhVm1hL$##*8###'A3/LkKW+(^rWX?5W_8g)a(m&K8P>#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(\"\n    \"P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs\"\n    \"bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTG&#1T5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q\"\n    \"h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aeg<Z'<$#4H)6,>e0jT6'N#(q%.O=?2S]u*(m<-\"\n    \"V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i\"\n    \"sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P&#9r+$%CE=68>K8r0=dSC%%(@p7\"\n    \".m7jilQ02'0-VWAg<a/''3u.=4L$Y)6k/K:_[3=&jvL<L0C/2'v:^;-DIBW,B4E68:kZ;%?8(Q8BH=kO65BW?xSG&#@uU,DS*,?.+(o(#1vCS8#CHF>TlGW'b)Tq7VT9q^*^$$.:&N@@\"\n    \"$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*\"\n    \"hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u\"\n    \"@-W$U%VEQ/,,>>#)D<h#`)h0:<Q6909ua+&VU%n2:cG3FJ-%@Bj-DgLr`Hw&HAKjKjseK</xKT*)B,N9X3]krc12t'pgTV(Lv-tL[xg_%=M_q7a^x?7Ubd>#%8cY#YZ?=,`Wdxu/ae&#\"\n    \"w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$s<Eh#c&)q.MXI%#v9ROa5FZO%sF7q7Nwb&#ptUJ:aqJe$Sl68%.D###EC><?-aF&#RNQv>o8lKN%5/$(vdfq7+ebA#\"\n    \"u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(<c`Q8N)jEIF*+?P2a8g%)$q]o2aH8C&<SibC/q,(e:v;-b#6[$NtDZ84Je2KNvB#$P5?tQ3nt(0\"\n    \"d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoF&#4DoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8\"\n    \"6e%B/:=>)N4xeW.*wft-;$'58-ESqr<b?UI(_%@[P46>#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#\"\n    \"b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjL<Lni;''X.`$#8+1GD\"\n    \":k$YUWsbn8ogh6rxZ2Z9]%nd+>V#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#<NEdtg(n'=S1A(Q1/I&4([%dM`,Iu'1:_hL>SfD07&6D<fp8dHM7/g+\"\n    \"tlPN9J*rKaPct&?'uBCem^jn%9_K)<,C5K3s=5g&GmJb*[SYq7K;TRLGCsM-$$;S%:Y@r7AK0pprpL<Lrh,q7e/%KWK:50I^+m'vi`3?%Zp+<-d+$L-Sv:@.o19n$s0&39;kn;S%BSq*\"\n    \"$3WoJSCLweV[aZ'MQIjO<7;X-X;&+dMLvu#^UsGEC9WEc[X(wI7#2.(F0jV*eZf<-Qv3J-c+J5AlrB#$p(H68LvEA'q3n0#m,[`*8Ft)FcYgEud]CWfm68,(aLA$@EFTgLXoBq/UPlp7\"\n    \":d[/;r_ix=:TF`S5H-b<LI&HY(K=h#)]Lk$K14lVfm:x$H<3^Ql<M`$OhapBnkup'D#L$Pb_`N*g]2e;X/Dtg,bsj&K#2[-:iYr'_wgH)NUIR8a1n#S?Yej'h8^58UbZd+^FKD*T@;6A\"\n    \"7aQC[K8d-(v6GI$x:T<&'Gp5Uf>@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-<aN((^7('#Z0wK#5GX@7\"\n    \"u][`*S^43933A4rl][`*O4CgLEl]v$1Q3AeF37dbXk,.)vj#x'd`;qgbQR%FW,2(?LO=s%Sc68%NP'##Aotl8x=BE#j1UD([3$M(]UI2LX3RpKN@;/#f'f/&_mt&F)XdF<9t4)Qa.*kT\"\n    \"LwQ'(TTB9.xH'>#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5<N?)NBS)QN*_I,?&)2'IM%L3I)X((e/dl2&8'<M\"\n    \":^#M*Q+[T.Xri.LYS3v%fF`68h;b-X[/En'CR.q7E)p'/kle2HM,u;^%OKC-N+Ll%F9CF<Nf'^#t2L,;27W:0O@6##U6W7:$rJfLWHj$#)woqBefIZ.PK<b*t7ed;p*_m;4ExK#h@&]>\"\n    \"_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%\"\n    \"hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;\"\n    \"^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmL<LD)F^%[tC'8;+9E#C$g%#5Y>q9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:\"\n    \"+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3<n-&%H%b<FDj2M<hH=&Eh<2Len$b*aTX=-8QxN)k11IM1c^j%\"\n    \"9s<L<NFSo)B?+<-(GxsF,^-Eh@$4dXhN$+#rxK8'je'D7k`e;)2pYwPA'_p9&@^18ml1^[@g4t*[JOa*[=Qp7(qJ_oOL^('7fB&Hq-:sf,sNj8xq^>$U4O]GKx'm9)b@p7YsvK3w^YR-\"\n    \"CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*\"\n    \"hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdF<TddF<9Ah-6&9tWoDlh]&1SpGMq>Ti1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IX<N+T+0MlMBPQ*Vj>SsD<U4JHY\"\n    \"8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-\"\n    \"S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n<bhPmUkMw>%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL<LoNs'6,'85`\"\n    \"0?t/'_U59@]ddF<#LdF<eWdF<OuN/45rY<-L@&#+fm>69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdF<gR@2L=FNU-<b[(9c/ML3m;Z[$oF3g)GAWqpARc=<ROu7cL5l;-[A]%/\"\n    \"+fsd;l#SafT/f*W]0=O'$(Tb<[)*@e775R-:Yob%g*>l*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj\"\n    \"M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#<IGe;__.thjZl<%w(Wk2xmp4Q@I#I9,DF]u7-P=.-_:YJ]aS@V\"\n    \"?6*C()dOp7:WL,b&3Rg/.cmM9&r^>$(>.Z-I&J(Q0Hd5Q%7Co-b`-c<N(6r@ip+AurK<m86QIth*#v;-OBqi+L7wDE-Ir8K['m+DDSLwK&/.?-V%U_%3:qKNu$_b*B-kp7NaD'QdWQPK\"\n    \"Yq[@>P)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8<FfNkgg^oIbah*#8/Qt$F&:K*-(N/'+1vMB,u()-a.VUU*#[e%gAAO(S>WlA2);Sa\"\n    \">gXm8YB`1d@K#n]76-a$U,mF<fX]idqd)<3,]J7JmW4`6]uks=4-72L(jEk+:bJ0M^q-8Dm_Z?0olP1C9Sa&H[d&c$ooQUj]Exd*3ZM@-WGW2%s',B-_M%>%Ul:#/'xoFM9QX-$.QN'>\"\n    \"[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B</R90;eZ]%Ncq;-Tl]#F>2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I\"\n    \"wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1<Vc52=u`3^o-n1'g4v58Hj&6_t7$##?M)c<$bgQ_'SY((-xkA#\"\n    \"Y(,p'H9rIVY-b,'%bCPF7.J<Up^,(dU1VY*5#WkTU>h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-u<Hp,3@e^9UB1J+ak9-TN/mhKPg+AJYd$\"\n    \"MlvAF_jCK*.O-^(63adMT->W%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)\"\n    \"i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo\"\n    \"1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P\"\n    \"iDDG)g,r%+?,$@?uou5tSe2aN_AQU*<h`e-GI7)?OK2A.d7_c)?wQ5AS@DL3r#7fSkgl6-++D:'A,uq7SvlB$pcpH'q3n0#_%dY#xCpr-l<F0NR@-##FEV6NTF6##$l84N1w?AO>'IAO\"\n    \"URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#\"\n    \";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T<XoIB&hx=T1PcDaB&;HH+-AFr?(m9HZV)FKS8JCw;SD=6[^/DZUL`EUDf]GGlG&>\"\n    \"w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#<xU?#@.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#]-=A#a9OA#\"\n    \"d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4&#3^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4\"\n    \"A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#\"\n    \"/QHC#3^ZC#7jmC#;v)D#?,<D#C8ND#GDaD#KPsD#O]/E#g1A5#KA*1#gC17#MGd;#8(02#L-d3#rWM4#Hga1#,<w0#T.j<#O#'2#CYN1#qa^:#_4m3#o@/=#eG8=#t8J5#`+78#4uI-#\"\n    \"m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#%/e0#\"\n    \"TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP\"\n    \"GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp\"\n    \"O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#\";\n\n#endif /* NK_INCLUDE_DEFAULT_FONT */\n\n#define NK_CURSOR_DATA_W 90\n#define NK_CURSOR_DATA_H 27\nNK_GLOBAL const char nk_custom_cursor_data[NK_CURSOR_DATA_W * NK_CURSOR_DATA_H + 1] =\n{\n    \"..-         -XXXXXXX-    X    -           X           -XXXXXXX          -          XXXXXXX\"\n    \"..-         -X.....X-   X.X   -          X.X          -X.....X          -          X.....X\"\n    \"---         -XXX.XXX-  X...X  -         X...X         -X....X           -           X....X\"\n    \"X           -  X.X  - X.....X -        X.....X        -X...X            -            X...X\"\n    \"XX          -  X.X  -X.......X-       X.......X       -X..X.X           -           X.X..X\"\n    \"X.X         -  X.X  -XXXX.XXXX-       XXXX.XXXX       -X.X X.X          -          X.X X.X\"\n    \"X..X        -  X.X  -   X.X   -          X.X          -XX   X.X         -         X.X   XX\"\n    \"X...X       -  X.X  -   X.X   -    XX    X.X    XX    -      X.X        -        X.X      \"\n    \"X....X      -  X.X  -   X.X   -   X.X    X.X    X.X   -       X.X       -       X.X       \"\n    \"X.....X     -  X.X  -   X.X   -  X..X    X.X    X..X  -        X.X      -      X.X        \"\n    \"X......X    -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -         X.X   XX-XX   X.X         \"\n    \"X.......X   -  X.X  -   X.X   -X.....................X-          X.X X.X-X.X X.X          \"\n    \"X........X  -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -           X.X..X-X..X.X           \"\n    \"X.........X -XXX.XXX-   X.X   -  X..X    X.X    X..X  -            X...X-X...X            \"\n    \"X..........X-X.....X-   X.X   -   X.X    X.X    X.X   -           X....X-X....X           \"\n    \"X......XXXXX-XXXXXXX-   X.X   -    XX    X.X    XX    -          X.....X-X.....X          \"\n    \"X...X..X    ---------   X.X   -          X.X          -          XXXXXXX-XXXXXXX          \"\n    \"X..X X..X   -       -XXXX.XXXX-       XXXX.XXXX       ------------------------------------\"\n    \"X.X  X..X   -       -X.......X-       X.......X       -    XX           XX    -           \"\n    \"XX    X..X  -       - X.....X -        X.....X        -   X.X           X.X   -           \"\n    \"      X..X          -  X...X  -         X...X         -  X..X           X..X  -           \"\n    \"       XX           -   X.X   -          X.X          - X...XXXXXXXXXXXXX...X -           \"\n    \"------------        -    X    -           X           -X.....................X-           \"\n    \"                    ----------------------------------- X...XXXXXXXXXXXXX...X -           \"\n    \"                                                      -  X..X           X..X  -           \"\n    \"                                                      -   X.X           X.X   -           \"\n    \"                                                      -    XX           XX    -           \"\n};\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#elif defined(__GNUC__) || defined(__GNUG__)\n#pragma GCC diagnostic pop\n#endif\n\nNK_GLOBAL unsigned char *nk__barrier;\nNK_GLOBAL unsigned char *nk__barrier2;\nNK_GLOBAL unsigned char *nk__barrier3;\nNK_GLOBAL unsigned char *nk__barrier4;\nNK_GLOBAL unsigned char *nk__dout;\n\nNK_INTERN unsigned int\nnk_decompress_length(unsigned char *input)\n{\n    return (unsigned int)((input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]);\n}\nNK_INTERN void\nnk__match(unsigned char *data, unsigned int length)\n{\n    /* INVERSE of memmove... write each byte before copying the next...*/\n    NK_ASSERT (nk__dout + length <= nk__barrier);\n    if (nk__dout + length > nk__barrier) { nk__dout += length; return; }\n    if (data < nk__barrier4) { nk__dout = nk__barrier+1; return; }\n    while (length--) *nk__dout++ = *data++;\n}\nNK_INTERN void\nnk__lit(unsigned char *data, unsigned int length)\n{\n    NK_ASSERT (nk__dout + length <= nk__barrier);\n    if (nk__dout + length > nk__barrier) { nk__dout += length; return; }\n    if (data < nk__barrier2) { nk__dout = nk__barrier+1; return; }\n    NK_MEMCPY(nk__dout, data, length);\n    nk__dout += length;\n}\nNK_INTERN unsigned char*\nnk_decompress_token(unsigned char *i)\n{\n    #define nk__in2(x)   ((i[x] << 8) + i[(x)+1])\n    #define nk__in3(x)   ((i[x] << 16) + nk__in2((x)+1))\n    #define nk__in4(x)   ((i[x] << 24) + nk__in3((x)+1))\n\n    if (*i >= 0x20) { /* use fewer if's for cases that expand small */\n        if (*i >= 0x80)       nk__match(nk__dout-i[1]-1, (unsigned int)i[0] - 0x80 + 1), i += 2;\n        else if (*i >= 0x40)  nk__match(nk__dout-(nk__in2(0) - 0x4000 + 1), (unsigned int)i[2]+1), i += 3;\n        else /* *i >= 0x20 */ nk__lit(i+1, (unsigned int)i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);\n    } else { /* more ifs for cases that expand large, since overhead is amortized */\n        if (*i >= 0x18)       nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x180000 + 1), (unsigned int)i[3]+1), i += 4;\n        else if (*i >= 0x10)  nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x100000 + 1), (unsigned int)nk__in2(3)+1), i += 5;\n        else if (*i >= 0x08)  nk__lit(i+2, (unsigned int)nk__in2(0) - 0x0800 + 1), i += 2 + (nk__in2(0) - 0x0800 + 1);\n        else if (*i == 0x07)  nk__lit(i+3, (unsigned int)nk__in2(1) + 1), i += 3 + (nk__in2(1) + 1);\n        else if (*i == 0x06)  nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), i[4]+1u), i += 5;\n        else if (*i == 0x04)  nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), (unsigned int)nk__in2(4)+1u), i += 6;\n    }\n    return i;\n}\nNK_INTERN unsigned int\nnk_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)\n{\n    const unsigned long ADLER_MOD = 65521;\n    unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;\n    unsigned long blocklen, i;\n\n    blocklen = buflen % 5552;\n    while (buflen) {\n        for (i=0; i + 7 < blocklen; i += 8) {\n            s1 += buffer[0]; s2 += s1;\n            s1 += buffer[1]; s2 += s1;\n            s1 += buffer[2]; s2 += s1;\n            s1 += buffer[3]; s2 += s1;\n            s1 += buffer[4]; s2 += s1;\n            s1 += buffer[5]; s2 += s1;\n            s1 += buffer[6]; s2 += s1;\n            s1 += buffer[7]; s2 += s1;\n            buffer += 8;\n        }\n        for (; i < blocklen; ++i) {\n            s1 += *buffer++; s2 += s1;\n        }\n\n        s1 %= ADLER_MOD; s2 %= ADLER_MOD;\n        buflen -= (unsigned int)blocklen;\n        blocklen = 5552;\n    }\n    return (unsigned int)(s2 << 16) + (unsigned int)s1;\n}\nNK_INTERN unsigned int\nnk_decompress(unsigned char *output, unsigned char *i, unsigned int length)\n{\n    unsigned int olen;\n    if (nk__in4(0) != 0x57bC0000) return 0;\n    if (nk__in4(4) != 0)          return 0; /* error! stream is > 4GB */\n    olen = nk_decompress_length(i);\n    nk__barrier2 = i;\n    nk__barrier3 = i+length;\n    nk__barrier = output + olen;\n    nk__barrier4 = output;\n    i += 16;\n\n    nk__dout = output;\n    for (;;) {\n        unsigned char *old_i = i;\n        i = nk_decompress_token(i);\n        if (i == old_i) {\n            if (*i == 0x05 && i[1] == 0xfa) {\n                NK_ASSERT(nk__dout == output + olen);\n                if (nk__dout != output + olen) return 0;\n                if (nk_adler32(1, output, olen) != (unsigned int) nk__in4(2))\n                    return 0;\n                return olen;\n            } else {\n                NK_ASSERT(0); /* NOTREACHED */\n                return 0;\n            }\n        }\n        NK_ASSERT(nk__dout <= output + olen);\n        if (nk__dout > output + olen)\n            return 0;\n    }\n}\nNK_INTERN unsigned int\nnk_decode_85_byte(char c)\n{\n    return (unsigned int)((c >= '\\\\') ? c-36 : c-35);\n}\nNK_INTERN void\nnk_decode_85(unsigned char* dst, const unsigned char* src)\n{\n    while (*src)\n    {\n        unsigned int tmp =\n            nk_decode_85_byte((char)src[0]) +\n            85 * (nk_decode_85_byte((char)src[1]) +\n            85 * (nk_decode_85_byte((char)src[2]) +\n            85 * (nk_decode_85_byte((char)src[3]) +\n            85 * nk_decode_85_byte((char)src[4]))));\n\n        /* we can't assume little-endianess. */\n        dst[0] = (unsigned char)((tmp >> 0) & 0xFF);\n        dst[1] = (unsigned char)((tmp >> 8) & 0xFF);\n        dst[2] = (unsigned char)((tmp >> 16) & 0xFF);\n        dst[3] = (unsigned char)((tmp >> 24) & 0xFF);\n\n        src += 5;\n        dst += 4;\n    }\n}\n\n/* -------------------------------------------------------------\n *\n *                          FONT ATLAS\n *\n * --------------------------------------------------------------*/\nNK_API struct nk_font_config\nnk_font_config(float pixel_height)\n{\n    struct nk_font_config cfg;\n    nk_zero_struct(cfg);\n    cfg.ttf_blob = 0;\n    cfg.ttf_size = 0;\n    cfg.ttf_data_owned_by_atlas = 0;\n    cfg.size = pixel_height;\n    cfg.oversample_h = 3;\n    cfg.oversample_v = 1;\n    cfg.pixel_snap = 0;\n    cfg.coord_type = NK_COORD_UV;\n    cfg.spacing = nk_vec2(0,0);\n    cfg.range = nk_font_default_glyph_ranges();\n    cfg.merge_mode = 0;\n    cfg.fallback_glyph = '?';\n    cfg.font = 0;\n    cfg.n = 0;\n    return cfg;\n}\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void\nnk_font_atlas_init_default(struct nk_font_atlas *atlas)\n{\n    NK_ASSERT(atlas);\n    if (!atlas) return;\n    nk_zero_struct(*atlas);\n    atlas->temporary.userdata.ptr = 0;\n    atlas->temporary.alloc = nk_malloc;\n    atlas->temporary.free = nk_mfree;\n    atlas->permanent.userdata.ptr = 0;\n    atlas->permanent.alloc = nk_malloc;\n    atlas->permanent.free = nk_mfree;\n}\n#endif\nNK_API void\nnk_font_atlas_init(struct nk_font_atlas *atlas, const struct nk_allocator *alloc)\n{\n    NK_ASSERT(atlas);\n    NK_ASSERT(alloc);\n    if (!atlas || !alloc) return;\n    nk_zero_struct(*atlas);\n    atlas->permanent = *alloc;\n    atlas->temporary = *alloc;\n}\nNK_API void\nnk_font_atlas_init_custom(struct nk_font_atlas *atlas,\n    const struct nk_allocator *permanent, const struct nk_allocator *temporary)\n{\n    NK_ASSERT(atlas);\n    NK_ASSERT(permanent);\n    NK_ASSERT(temporary);\n    if (!atlas || !permanent || !temporary) return;\n    nk_zero_struct(*atlas);\n    atlas->permanent = *permanent;\n    atlas->temporary = *temporary;\n}\nNK_API void\nnk_font_atlas_begin(struct nk_font_atlas *atlas)\n{\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc && atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc && atlas->permanent.free);\n    if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free ||\n        !atlas->temporary.alloc || !atlas->temporary.free) return;\n    if (atlas->glyphs) {\n        atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);\n        atlas->glyphs = 0;\n    }\n    if (atlas->pixel) {\n        atlas->permanent.free(atlas->permanent.userdata, atlas->pixel);\n        atlas->pixel = 0;\n    }\n}\nNK_API struct nk_font*\nnk_font_atlas_add(struct nk_font_atlas *atlas, const struct nk_font_config *config)\n{\n    struct nk_font *font = 0;\n    struct nk_font_config *cfg;\n\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n\n    NK_ASSERT(config);\n    NK_ASSERT(config->ttf_blob);\n    NK_ASSERT(config->ttf_size);\n    NK_ASSERT(config->size > 0.0f);\n\n    if (!atlas || !config || !config->ttf_blob || !config->ttf_size || config->size <= 0.0f||\n        !atlas->permanent.alloc || !atlas->permanent.free ||\n        !atlas->temporary.alloc || !atlas->temporary.free)\n        return 0;\n\n    /* allocate font config  */\n    cfg = (struct nk_font_config*)\n        atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font_config));\n    NK_MEMCPY(cfg, config, sizeof(*config));\n    cfg->n = cfg;\n    cfg->p = cfg;\n\n    if (!config->merge_mode) {\n        /* insert font config into list */\n        if (!atlas->config) {\n            atlas->config = cfg;\n            cfg->next = 0;\n        } else {\n            struct nk_font_config *i = atlas->config;\n            while (i->next) i = i->next;\n            i->next = cfg;\n            cfg->next = 0;\n        }\n        /* allocate new font */\n        font = (struct nk_font*)\n            atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font));\n        NK_ASSERT(font);\n        nk_zero(font, sizeof(*font));\n        if (!font) return 0;\n        font->config = cfg;\n\n        /* insert font into list */\n        if (!atlas->fonts) {\n            atlas->fonts = font;\n            font->next = 0;\n        } else {\n            struct nk_font *i = atlas->fonts;\n            while (i->next) i = i->next;\n            i->next = font;\n            font->next = 0;\n        }\n        cfg->font = &font->info;\n    } else {\n        /* extend previously added font */\n        struct nk_font *f = 0;\n        struct nk_font_config *c = 0;\n        NK_ASSERT(atlas->font_num);\n        f = atlas->fonts;\n        c = f->config;\n        cfg->font = &f->info;\n\n        cfg->n = c;\n        cfg->p = c->p;\n        c->p->n = cfg;\n        c->p = cfg;\n    }\n    /* create own copy of .TTF font blob */\n    if (!config->ttf_data_owned_by_atlas) {\n        cfg->ttf_blob = atlas->permanent.alloc(atlas->permanent.userdata,0, cfg->ttf_size);\n        NK_ASSERT(cfg->ttf_blob);\n        if (!cfg->ttf_blob) {\n            atlas->font_num++;\n            return 0;\n        }\n        NK_MEMCPY(cfg->ttf_blob, config->ttf_blob, cfg->ttf_size);\n        cfg->ttf_data_owned_by_atlas = 1;\n    }\n    atlas->font_num++;\n    return font;\n}\nNK_API struct nk_font*\nnk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory,\n    nk_size size, float height, const struct nk_font_config *config)\n{\n    struct nk_font_config cfg;\n    NK_ASSERT(memory);\n    NK_ASSERT(size);\n\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n    if (!atlas || !atlas->temporary.alloc || !atlas->temporary.free || !memory || !size ||\n        !atlas->permanent.alloc || !atlas->permanent.free)\n        return 0;\n\n    cfg = (config) ? *config: nk_font_config(height);\n    cfg.ttf_blob = memory;\n    cfg.ttf_size = size;\n    cfg.size = height;\n    cfg.ttf_data_owned_by_atlas = 0;\n    return nk_font_atlas_add(atlas, &cfg);\n}\n#ifdef NK_INCLUDE_STANDARD_IO\nNK_API struct nk_font*\nnk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path,\n    float height, const struct nk_font_config *config)\n{\n    nk_size size;\n    char *memory;\n    struct nk_font_config cfg;\n\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n\n    if (!atlas || !file_path) return 0;\n    memory = nk_file_load(file_path, &size, &atlas->permanent);\n    if (!memory) return 0;\n\n    cfg = (config) ? *config: nk_font_config(height);\n    cfg.ttf_blob = memory;\n    cfg.ttf_size = size;\n    cfg.size = height;\n    cfg.ttf_data_owned_by_atlas = 1;\n    return nk_font_atlas_add(atlas, &cfg);\n}\n#endif\nNK_API struct nk_font*\nnk_font_atlas_add_compressed(struct nk_font_atlas *atlas,\n    void *compressed_data, nk_size compressed_size, float height,\n    const struct nk_font_config *config)\n{\n    unsigned int decompressed_size;\n    void *decompressed_data;\n    struct nk_font_config cfg;\n\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n\n    NK_ASSERT(compressed_data);\n    NK_ASSERT(compressed_size);\n    if (!atlas || !compressed_data || !atlas->temporary.alloc || !atlas->temporary.free ||\n        !atlas->permanent.alloc || !atlas->permanent.free)\n        return 0;\n\n    decompressed_size = nk_decompress_length((unsigned char*)compressed_data);\n    decompressed_data = atlas->permanent.alloc(atlas->permanent.userdata,0,decompressed_size);\n    NK_ASSERT(decompressed_data);\n    if (!decompressed_data) return 0;\n    nk_decompress((unsigned char*)decompressed_data, (unsigned char*)compressed_data,\n        (unsigned int)compressed_size);\n\n    cfg = (config) ? *config: nk_font_config(height);\n    cfg.ttf_blob = decompressed_data;\n    cfg.ttf_size = decompressed_size;\n    cfg.size = height;\n    cfg.ttf_data_owned_by_atlas = 1;\n    return nk_font_atlas_add(atlas, &cfg);\n}\nNK_API struct nk_font*\nnk_font_atlas_add_compressed_base85(struct nk_font_atlas *atlas,\n    const char *data_base85, float height, const struct nk_font_config *config)\n{\n    int compressed_size;\n    void *compressed_data;\n    struct nk_font *font;\n\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n\n    NK_ASSERT(data_base85);\n    if (!atlas || !data_base85 || !atlas->temporary.alloc || !atlas->temporary.free ||\n        !atlas->permanent.alloc || !atlas->permanent.free)\n        return 0;\n\n    compressed_size = (((int)nk_strlen(data_base85) + 4) / 5) * 4;\n    compressed_data = atlas->temporary.alloc(atlas->temporary.userdata,0, (nk_size)compressed_size);\n    NK_ASSERT(compressed_data);\n    if (!compressed_data) return 0;\n    nk_decode_85((unsigned char*)compressed_data, (const unsigned char*)data_base85);\n    font = nk_font_atlas_add_compressed(atlas, compressed_data,\n                    (nk_size)compressed_size, height, config);\n    atlas->temporary.free(atlas->temporary.userdata, compressed_data);\n    return font;\n}\n\n#ifdef NK_INCLUDE_DEFAULT_FONT\nNK_API struct nk_font*\nnk_font_atlas_add_default(struct nk_font_atlas *atlas,\n    float pixel_height, const struct nk_font_config *config)\n{\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n    return nk_font_atlas_add_compressed_base85(atlas,\n        nk_proggy_clean_ttf_compressed_data_base85, pixel_height, config);\n}\n#endif\nNK_API const void*\nnk_font_atlas_bake(struct nk_font_atlas *atlas, int *width, int *height,\n    enum nk_font_atlas_format fmt)\n{\n    int i = 0;\n    void *tmp = 0;\n    nk_size tmp_size, img_size;\n    struct nk_font *font_iter;\n    struct nk_font_baker *baker;\n\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n\n    NK_ASSERT(width);\n    NK_ASSERT(height);\n    if (!atlas || !width || !height ||\n        !atlas->temporary.alloc || !atlas->temporary.free ||\n        !atlas->permanent.alloc || !atlas->permanent.free)\n        return 0;\n\n#ifdef NK_INCLUDE_DEFAULT_FONT\n    /* no font added so just use default font */\n    if (!atlas->font_num)\n        atlas->default_font = nk_font_atlas_add_default(atlas, 13.0f, 0);\n#endif\n    NK_ASSERT(atlas->font_num);\n    if (!atlas->font_num) return 0;\n\n    /* allocate temporary baker memory required for the baking process */\n    nk_font_baker_memory(&tmp_size, &atlas->glyph_count, atlas->config, atlas->font_num);\n    tmp = atlas->temporary.alloc(atlas->temporary.userdata,0, tmp_size);\n    NK_ASSERT(tmp);\n    if (!tmp) goto failed;\n    NK_MEMSET(tmp,0,tmp_size);\n\n    /* allocate glyph memory for all fonts */\n    baker = nk_font_baker(tmp, atlas->glyph_count, atlas->font_num, &atlas->temporary);\n    atlas->glyphs = (struct nk_font_glyph*)atlas->permanent.alloc(\n        atlas->permanent.userdata,0, sizeof(struct nk_font_glyph)*(nk_size)atlas->glyph_count);\n    NK_ASSERT(atlas->glyphs);\n    if (!atlas->glyphs)\n        goto failed;\n\n    /* pack all glyphs into a tight fit space */\n    atlas->custom.w = (NK_CURSOR_DATA_W*2)+1;\n    atlas->custom.h = NK_CURSOR_DATA_H + 1;\n    if (!nk_font_bake_pack(baker, &img_size, width, height, &atlas->custom,\n        atlas->config, atlas->font_num, &atlas->temporary))\n        goto failed;\n\n    /* allocate memory for the baked image font atlas */\n    atlas->pixel = atlas->temporary.alloc(atlas->temporary.userdata,0, img_size);\n    NK_ASSERT(atlas->pixel);\n    if (!atlas->pixel)\n        goto failed;\n\n    /* bake glyphs and custom white pixel into image */\n    nk_font_bake(baker, atlas->pixel, *width, *height,\n        atlas->glyphs, atlas->glyph_count, atlas->config, atlas->font_num);\n    nk_font_bake_custom_data(atlas->pixel, *width, *height, atlas->custom,\n            nk_custom_cursor_data, NK_CURSOR_DATA_W, NK_CURSOR_DATA_H, '.', 'X');\n\n    if (fmt == NK_FONT_ATLAS_RGBA32) {\n        /* convert alpha8 image into rgba32 image */\n        void *img_rgba = atlas->temporary.alloc(atlas->temporary.userdata,0,\n                            (nk_size)(*width * *height * 4));\n        NK_ASSERT(img_rgba);\n        if (!img_rgba) goto failed;\n        nk_font_bake_convert(img_rgba, *width, *height, atlas->pixel);\n        atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);\n        atlas->pixel = img_rgba;\n    }\n    atlas->tex_width = *width;\n    atlas->tex_height = *height;\n\n    /* initialize each font */\n    for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) {\n        struct nk_font *font = font_iter;\n        struct nk_font_config *config = font->config;\n        nk_font_init(font, config->size, config->fallback_glyph, atlas->glyphs,\n            config->font, nk_handle_ptr(0));\n    }\n\n    /* initialize each cursor */\n    {NK_STORAGE const struct nk_vec2 nk_cursor_data[NK_CURSOR_COUNT][3] = {\n        /* Pos      Size        Offset */\n        {{ 0, 3},   {12,19},    { 0, 0}},\n        {{13, 0},   { 7,16},    { 4, 8}},\n        {{31, 0},   {23,23},    {11,11}},\n        {{21, 0},   { 9, 23},   { 5,11}},\n        {{55,18},   {23, 9},    {11, 5}},\n        {{73, 0},   {17,17},    { 9, 9}},\n        {{55, 0},   {17,17},    { 9, 9}}\n    };\n    for (i = 0; i < NK_CURSOR_COUNT; ++i) {\n        struct nk_cursor *cursor = &atlas->cursors[i];\n        cursor->img.w = (unsigned short)*width;\n        cursor->img.h = (unsigned short)*height;\n        cursor->img.region[0] = (unsigned short)(atlas->custom.x + nk_cursor_data[i][0].x);\n        cursor->img.region[1] = (unsigned short)(atlas->custom.y + nk_cursor_data[i][0].y);\n        cursor->img.region[2] = (unsigned short)nk_cursor_data[i][1].x;\n        cursor->img.region[3] = (unsigned short)nk_cursor_data[i][1].y;\n        cursor->size = nk_cursor_data[i][1];\n        cursor->offset = nk_cursor_data[i][2];\n    }}\n    /* free temporary memory */\n    atlas->temporary.free(atlas->temporary.userdata, tmp);\n    return atlas->pixel;\n\nfailed:\n    /* error so cleanup all memory */\n    if (tmp) atlas->temporary.free(atlas->temporary.userdata, tmp);\n    if (atlas->glyphs) {\n        atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);\n        atlas->glyphs = 0;\n    }\n    if (atlas->pixel) {\n        atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);\n        atlas->pixel = 0;\n    }\n    return 0;\n}\nNK_API void\nnk_font_atlas_end(struct nk_font_atlas *atlas, nk_handle texture,\n    struct nk_draw_null_texture *tex_null)\n{\n    int i = 0;\n    struct nk_font *font_iter;\n    NK_ASSERT(atlas);\n    if (!atlas) {\n        if (!tex_null) return;\n        tex_null->texture = texture;\n        tex_null->uv = nk_vec2(0.5f,0.5f);\n    }\n    if (tex_null) {\n        tex_null->texture = texture;\n        tex_null->uv.x = (atlas->custom.x + 0.5f)/(float)atlas->tex_width;\n        tex_null->uv.y = (atlas->custom.y + 0.5f)/(float)atlas->tex_height;\n    }\n    for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) {\n        font_iter->texture = texture;\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n        font_iter->handle.texture = texture;\n#endif\n    }\n    for (i = 0; i < NK_CURSOR_COUNT; ++i)\n        atlas->cursors[i].img.handle = texture;\n\n    atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);\n    atlas->pixel = 0;\n    atlas->tex_width = 0;\n    atlas->tex_height = 0;\n    atlas->custom.x = 0;\n    atlas->custom.y = 0;\n    atlas->custom.w = 0;\n    atlas->custom.h = 0;\n}\nNK_API void\nnk_font_atlas_cleanup(struct nk_font_atlas *atlas)\n{\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n    if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return;\n    if (atlas->config) {\n        struct nk_font_config *iter;\n        for (iter = atlas->config; iter; iter = iter->next) {\n            struct nk_font_config *i;\n            for (i = iter->n; i != iter; i = i->n) {\n                atlas->permanent.free(atlas->permanent.userdata, i->ttf_blob);\n                i->ttf_blob = 0;\n            }\n            atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob);\n            iter->ttf_blob = 0;\n        }\n    }\n}\nNK_API void\nnk_font_atlas_clear(struct nk_font_atlas *atlas)\n{\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n    if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return;\n\n    if (atlas->config) {\n        struct nk_font_config *iter, *next;\n        for (iter = atlas->config; iter; iter = next) {\n            struct nk_font_config *i, *n;\n            for (i = iter->n; i != iter; i = n) {\n                n = i->n;\n                if (i->ttf_blob)\n                    atlas->permanent.free(atlas->permanent.userdata, i->ttf_blob);\n                atlas->permanent.free(atlas->permanent.userdata, i);\n            }\n            next = iter->next;\n            if (i->ttf_blob)\n                atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob);\n            atlas->permanent.free(atlas->permanent.userdata, iter);\n        }\n        atlas->config = 0;\n    }\n    if (atlas->fonts) {\n        struct nk_font *iter, *next;\n        for (iter = atlas->fonts; iter; iter = next) {\n            next = iter->next;\n            atlas->permanent.free(atlas->permanent.userdata, iter);\n        }\n        atlas->fonts = 0;\n    }\n    if (atlas->glyphs)\n        atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);\n    nk_zero_struct(*atlas);\n}\n#endif\n\n\n\n\n/* ===============================================================\n *\n *                          INPUT\n *\n * ===============================================================*/\nNK_API void\nnk_input_begin(struct nk_context *ctx)\n{\n    int i;\n    struct nk_input *in;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    in = &ctx->input;\n    for (i = 0; i < NK_BUTTON_MAX; ++i)\n        in->mouse.buttons[i].clicked = 0;\n\n    in->keyboard.text_len = 0;\n    in->mouse.scroll_delta = nk_vec2(0,0);\n    in->mouse.prev.x = in->mouse.pos.x;\n    in->mouse.prev.y = in->mouse.pos.y;\n    in->mouse.delta.x = 0;\n    in->mouse.delta.y = 0;\n    for (i = 0; i < NK_KEY_MAX; i++)\n        in->keyboard.keys[i].clicked = 0;\n}\nNK_API void\nnk_input_end(struct nk_context *ctx)\n{\n    struct nk_input *in;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    in = &ctx->input;\n    if (in->mouse.grab)\n        in->mouse.grab = 0;\n    if (in->mouse.ungrab) {\n        in->mouse.grabbed = 0;\n        in->mouse.ungrab = 0;\n        in->mouse.grab = 0;\n    }\n}\nNK_API void\nnk_input_motion(struct nk_context *ctx, int x, int y)\n{\n    struct nk_input *in;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    in = &ctx->input;\n    in->mouse.pos.x = (float)x;\n    in->mouse.pos.y = (float)y;\n    in->mouse.delta.x = in->mouse.pos.x - in->mouse.prev.x;\n    in->mouse.delta.y = in->mouse.pos.y - in->mouse.prev.y;\n}\nNK_API void\nnk_input_key(struct nk_context *ctx, enum nk_keys key, nk_bool down)\n{\n    struct nk_input *in;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    in = &ctx->input;\n#ifdef NK_KEYSTATE_BASED_INPUT\n    if (in->keyboard.keys[key].down != down)\n        in->keyboard.keys[key].clicked++;\n#else\n    in->keyboard.keys[key].clicked++;\n#endif\n    in->keyboard.keys[key].down = down;\n}\nNK_API void\nnk_input_button(struct nk_context *ctx, enum nk_buttons id, int x, int y, nk_bool down)\n{\n    struct nk_mouse_button *btn;\n    struct nk_input *in;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    in = &ctx->input;\n    if (in->mouse.buttons[id].down == down) return;\n\n    btn = &in->mouse.buttons[id];\n    btn->clicked_pos.x = (float)x;\n    btn->clicked_pos.y = (float)y;\n    btn->down = down;\n    btn->clicked++;\n\n    /* Fix Click-Drag for touch events. */\n    in->mouse.delta.x = 0;\n    in->mouse.delta.y = 0;\n#ifdef NK_BUTTON_TRIGGER_ON_RELEASE\n    if (down == 1 && id == NK_BUTTON_LEFT)\n    {\n        in->mouse.down_pos.x = btn->clicked_pos.x;\n        in->mouse.down_pos.y = btn->clicked_pos.y;\n    }\n#endif\n}\nNK_API void\nnk_input_scroll(struct nk_context *ctx, struct nk_vec2 val)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    ctx->input.mouse.scroll_delta.x += val.x;\n    ctx->input.mouse.scroll_delta.y += val.y;\n}\nNK_API void\nnk_input_glyph(struct nk_context *ctx, const nk_glyph glyph)\n{\n    int len = 0;\n    nk_rune unicode;\n    struct nk_input *in;\n\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    in = &ctx->input;\n\n    len = nk_utf_decode(glyph, &unicode, NK_UTF_SIZE);\n    if (len && ((in->keyboard.text_len + len) < NK_INPUT_MAX)) {\n        nk_utf_encode(unicode, &in->keyboard.text[in->keyboard.text_len],\n            NK_INPUT_MAX - in->keyboard.text_len);\n        in->keyboard.text_len += len;\n    }\n}\nNK_API void\nnk_input_char(struct nk_context *ctx, char c)\n{\n    nk_glyph glyph = {0};\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    glyph[0] = c;\n    nk_input_glyph(ctx, glyph);\n}\nNK_API void\nnk_input_unicode(struct nk_context *ctx, nk_rune unicode)\n{\n    nk_glyph rune;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    nk_utf_encode(unicode, rune, NK_UTF_SIZE);\n    nk_input_glyph(ctx, rune);\n}\nNK_API nk_bool\nnk_input_has_mouse_click(const struct nk_input *i, enum nk_buttons id)\n{\n    const struct nk_mouse_button *btn;\n    if (!i) return nk_false;\n    btn = &i->mouse.buttons[id];\n    return (btn->clicked && btn->down == nk_false) ? nk_true : nk_false;\n}\nNK_API nk_bool\nnk_input_has_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id,\n    struct nk_rect b)\n{\n    const struct nk_mouse_button *btn;\n    if (!i) return nk_false;\n    btn = &i->mouse.buttons[id];\n    if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h))\n        return nk_false;\n    return nk_true;\n}\nNK_API nk_bool\nnk_input_has_mouse_click_in_button_rect(const struct nk_input *i, enum nk_buttons id,\n    struct nk_rect b)\n{\n    const struct nk_mouse_button *btn;\n    if (!i) return nk_false;\n    btn = &i->mouse.buttons[id];\n#ifdef NK_BUTTON_TRIGGER_ON_RELEASE\n    if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h)\n        || !NK_INBOX(i->mouse.down_pos.x,i->mouse.down_pos.y,b.x,b.y,b.w,b.h))\n#else\n    if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h))\n#endif\n        return nk_false;\n    return nk_true;\n}\nNK_API nk_bool\nnk_input_has_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,\n    struct nk_rect b, nk_bool down)\n{\n    const struct nk_mouse_button *btn;\n    if (!i) return nk_false;\n    btn = &i->mouse.buttons[id];\n    return nk_input_has_mouse_click_in_rect(i, id, b) && (btn->down == down);\n}\nNK_API nk_bool\nnk_input_is_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id,\n    struct nk_rect b)\n{\n    const struct nk_mouse_button *btn;\n    if (!i) return nk_false;\n    btn = &i->mouse.buttons[id];\n    return (nk_input_has_mouse_click_down_in_rect(i, id, b, nk_false) &&\n            btn->clicked) ? nk_true : nk_false;\n}\nNK_API nk_bool\nnk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,\n    struct nk_rect b, nk_bool down)\n{\n    const struct nk_mouse_button *btn;\n    if (!i) return nk_false;\n    btn = &i->mouse.buttons[id];\n    return (nk_input_has_mouse_click_down_in_rect(i, id, b, down) &&\n            btn->clicked) ? nk_true : nk_false;\n}\nNK_API nk_bool\nnk_input_any_mouse_click_in_rect(const struct nk_input *in, struct nk_rect b)\n{\n    int i, down = 0;\n    for (i = 0; i < NK_BUTTON_MAX; ++i)\n        down = down || nk_input_is_mouse_click_in_rect(in, (enum nk_buttons)i, b);\n    return down;\n}\nNK_API nk_bool\nnk_input_is_mouse_hovering_rect(const struct nk_input *i, struct nk_rect rect)\n{\n    if (!i) return nk_false;\n    return NK_INBOX(i->mouse.pos.x, i->mouse.pos.y, rect.x, rect.y, rect.w, rect.h);\n}\nNK_API nk_bool\nnk_input_is_mouse_prev_hovering_rect(const struct nk_input *i, struct nk_rect rect)\n{\n    if (!i) return nk_false;\n    return NK_INBOX(i->mouse.prev.x, i->mouse.prev.y, rect.x, rect.y, rect.w, rect.h);\n}\nNK_API nk_bool\nnk_input_mouse_clicked(const struct nk_input *i, enum nk_buttons id, struct nk_rect rect)\n{\n    if (!i) return nk_false;\n    if (!nk_input_is_mouse_hovering_rect(i, rect)) return nk_false;\n    return nk_input_is_mouse_click_in_rect(i, id, rect);\n}\nNK_API nk_bool\nnk_input_is_mouse_down(const struct nk_input *i, enum nk_buttons id)\n{\n    if (!i) return nk_false;\n    return i->mouse.buttons[id].down;\n}\nNK_API nk_bool\nnk_input_is_mouse_pressed(const struct nk_input *i, enum nk_buttons id)\n{\n    const struct nk_mouse_button *b;\n    if (!i) return nk_false;\n    b = &i->mouse.buttons[id];\n    if (b->down && b->clicked)\n        return nk_true;\n    return nk_false;\n}\nNK_API nk_bool\nnk_input_is_mouse_released(const struct nk_input *i, enum nk_buttons id)\n{\n    if (!i) return nk_false;\n    return (!i->mouse.buttons[id].down && i->mouse.buttons[id].clicked);\n}\nNK_API nk_bool\nnk_input_is_mouse_moved(const struct nk_input *i)\n{\n    if (!i) return nk_false;\n    return i->mouse.delta.x != 0 || i->mouse.delta.y != 0;\n}\nNK_API nk_bool\nnk_input_is_key_pressed(const struct nk_input *i, enum nk_keys key)\n{\n    const struct nk_key *k;\n    if (!i) return nk_false;\n    k = &i->keyboard.keys[key];\n    if ((k->down && k->clicked) || (!k->down && k->clicked >= 2))\n        return nk_true;\n    return nk_false;\n}\nNK_API nk_bool\nnk_input_is_key_released(const struct nk_input *i, enum nk_keys key)\n{\n    const struct nk_key *k;\n    if (!i) return nk_false;\n    k = &i->keyboard.keys[key];\n    if ((!k->down && k->clicked) || (k->down && k->clicked >= 2))\n        return nk_true;\n    return nk_false;\n}\nNK_API nk_bool\nnk_input_is_key_down(const struct nk_input *i, enum nk_keys key)\n{\n    const struct nk_key *k;\n    if (!i) return nk_false;\n    k = &i->keyboard.keys[key];\n    if (k->down) return nk_true;\n    return nk_false;\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                              STYLE\n *\n * ===============================================================*/\nNK_API void nk_style_default(struct nk_context *ctx){nk_style_from_table(ctx, 0);}\n#define NK_COLOR_MAP(NK_COLOR)\\\n    NK_COLOR(NK_COLOR_TEXT,                     175,175,175,255) \\\n    NK_COLOR(NK_COLOR_WINDOW,                   45, 45, 45, 255) \\\n    NK_COLOR(NK_COLOR_HEADER,                   40, 40, 40, 255) \\\n    NK_COLOR(NK_COLOR_BORDER,                   65, 65, 65, 255) \\\n    NK_COLOR(NK_COLOR_BUTTON,                   50, 50, 50, 255) \\\n    NK_COLOR(NK_COLOR_BUTTON_HOVER,             40, 40, 40, 255) \\\n    NK_COLOR(NK_COLOR_BUTTON_ACTIVE,            35, 35, 35, 255) \\\n    NK_COLOR(NK_COLOR_TOGGLE,                   100,100,100,255) \\\n    NK_COLOR(NK_COLOR_TOGGLE_HOVER,             120,120,120,255) \\\n    NK_COLOR(NK_COLOR_TOGGLE_CURSOR,            45, 45, 45, 255) \\\n    NK_COLOR(NK_COLOR_SELECT,                   45, 45, 45, 255) \\\n    NK_COLOR(NK_COLOR_SELECT_ACTIVE,            35, 35, 35,255)  \\\n    NK_COLOR(NK_COLOR_SLIDER,                   38, 38, 38, 255) \\\n    NK_COLOR(NK_COLOR_SLIDER_CURSOR,            100,100,100,255) \\\n    NK_COLOR(NK_COLOR_SLIDER_CURSOR_HOVER,      120,120,120,255) \\\n    NK_COLOR(NK_COLOR_SLIDER_CURSOR_ACTIVE,     150,150,150,255) \\\n    NK_COLOR(NK_COLOR_PROPERTY,                 38, 38, 38, 255) \\\n    NK_COLOR(NK_COLOR_EDIT,                     38, 38, 38, 255) \\\n    NK_COLOR(NK_COLOR_EDIT_CURSOR,              175,175,175,255) \\\n    NK_COLOR(NK_COLOR_COMBO,                    45, 45, 45, 255) \\\n    NK_COLOR(NK_COLOR_CHART,                    120,120,120,255) \\\n    NK_COLOR(NK_COLOR_CHART_COLOR,              45, 45, 45, 255) \\\n    NK_COLOR(NK_COLOR_CHART_COLOR_HIGHLIGHT,    255, 0,  0, 255) \\\n    NK_COLOR(NK_COLOR_SCROLLBAR,                40, 40, 40, 255) \\\n    NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR,         100,100,100,255) \\\n    NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_HOVER,   120,120,120,255) \\\n    NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_ACTIVE,  150,150,150,255) \\\n    NK_COLOR(NK_COLOR_TAB_HEADER,               40, 40, 40,255)  \\\n    NK_COLOR(NK_COLOR_KNOB,                     38, 38, 38, 255) \\\n    NK_COLOR(NK_COLOR_KNOB_CURSOR,              100,100,100,255) \\\n    NK_COLOR(NK_COLOR_KNOB_CURSOR_HOVER,        120,120,120,255) \\\n    NK_COLOR(NK_COLOR_KNOB_CURSOR_ACTIVE,       150,150,150,255)\n\nNK_GLOBAL const struct nk_color\nnk_default_color_style[NK_COLOR_COUNT] = {\n#define NK_COLOR(a,b,c,d,e) {b,c,d,e},\n    NK_COLOR_MAP(NK_COLOR)\n#undef NK_COLOR\n};\nNK_GLOBAL const char *nk_color_names[NK_COLOR_COUNT] = {\n#define NK_COLOR(a,b,c,d,e) #a,\n    NK_COLOR_MAP(NK_COLOR)\n#undef NK_COLOR\n};\n\nNK_API const char*\nnk_style_get_color_by_name(enum nk_style_colors c)\n{\n    return nk_color_names[c];\n}\nNK_API struct nk_style_item\nnk_style_item_color(struct nk_color col)\n{\n    struct nk_style_item i;\n    i.type = NK_STYLE_ITEM_COLOR;\n    i.data.color = col;\n    return i;\n}\nNK_API struct nk_style_item\nnk_style_item_image(struct nk_image img)\n{\n    struct nk_style_item i;\n    i.type = NK_STYLE_ITEM_IMAGE;\n    i.data.image = img;\n    return i;\n}\nNK_API struct nk_style_item\nnk_style_item_nine_slice(struct nk_nine_slice slice)\n{\n    struct nk_style_item i;\n    i.type = NK_STYLE_ITEM_NINE_SLICE;\n    i.data.slice = slice;\n    return i;\n}\nNK_API struct nk_style_item\nnk_style_item_hide(void)\n{\n    struct nk_style_item i;\n    i.type = NK_STYLE_ITEM_COLOR;\n    i.data.color = nk_rgba(0,0,0,0);\n    return i;\n}\nNK_API void\nnk_style_from_table(struct nk_context *ctx, const struct nk_color *table)\n{\n    struct nk_style *style;\n    struct nk_style_text *text;\n    struct nk_style_button *button;\n    struct nk_style_toggle *toggle;\n    struct nk_style_selectable *select;\n    struct nk_style_slider *slider;\n    struct nk_style_knob *knob;\n    struct nk_style_progress *prog;\n    struct nk_style_scrollbar *scroll;\n    struct nk_style_edit *edit;\n    struct nk_style_property *property;\n    struct nk_style_combo *combo;\n    struct nk_style_chart *chart;\n    struct nk_style_tab *tab;\n    struct nk_style_window *win;\n\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    style = &ctx->style;\n    table = (!table) ? nk_default_color_style: table;\n\n    /* default text */\n    text = &style->text;\n    text->color = table[NK_COLOR_TEXT];\n    text->padding = nk_vec2(0,0);\n    text->color_factor = 1.0f;\n    text->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n\n    /* default button */\n    button = &style->button;\n    nk_zero_struct(*button);\n    button->normal                     = nk_style_item_color(table[NK_COLOR_BUTTON]);\n    button->hover                      = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]);\n    button->active                     = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]);\n    button->border_color               = table[NK_COLOR_BORDER];\n    button->text_background            = table[NK_COLOR_BUTTON];\n    button->text_normal                = table[NK_COLOR_TEXT];\n    button->text_hover                 = table[NK_COLOR_TEXT];\n    button->text_active                = table[NK_COLOR_TEXT];\n    button->padding                    = nk_vec2(2.0f,2.0f);\n    button->image_padding              = nk_vec2(0.0f,0.0f);\n    button->touch_padding              = nk_vec2(0.0f, 0.0f);\n    button->userdata                   = nk_handle_ptr(0);\n    button->text_alignment             = NK_TEXT_CENTERED;\n    button->border                     = 1.0f;\n    button->rounding                   = 4.0f;\n    button->color_factor_text          = 1.0f;\n    button->color_factor_background    = 1.0f;\n    button->disabled_factor            = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin                 = 0;\n    button->draw_end                   = 0;\n\n    /* contextual button */\n    button = &style->contextual_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]);\n    button->active          = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]);\n    button->border_color    = table[NK_COLOR_WINDOW];\n    button->text_background = table[NK_COLOR_WINDOW];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(2.0f,2.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n\n    /* menu button */\n    button = &style->menu_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->active          = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->border_color    = table[NK_COLOR_WINDOW];\n    button->text_background = table[NK_COLOR_WINDOW];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(2.0f,2.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 1.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n\n    /* checkbox toggle */\n    toggle = &style->checkbox;\n    nk_zero_struct(*toggle);\n    toggle->normal          = nk_style_item_color(table[NK_COLOR_TOGGLE]);\n    toggle->hover           = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);\n    toggle->active          = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);\n    toggle->cursor_normal   = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);\n    toggle->cursor_hover    = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);\n    toggle->userdata        = nk_handle_ptr(0);\n    toggle->text_background = table[NK_COLOR_WINDOW];\n    toggle->text_normal     = table[NK_COLOR_TEXT];\n    toggle->text_hover      = table[NK_COLOR_TEXT];\n    toggle->text_active     = table[NK_COLOR_TEXT];\n    toggle->padding         = nk_vec2(2.0f, 2.0f);\n    toggle->touch_padding   = nk_vec2(0,0);\n    toggle->border_color    = nk_rgba(0,0,0,0);\n    toggle->border          = 0.0f;\n    toggle->spacing         = 4;\n    toggle->color_factor    = 1.0f;\n    toggle->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n\n    /* option toggle */\n    toggle = &style->option;\n    nk_zero_struct(*toggle);\n    toggle->normal          = nk_style_item_color(table[NK_COLOR_TOGGLE]);\n    toggle->hover           = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);\n    toggle->active          = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);\n    toggle->cursor_normal   = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);\n    toggle->cursor_hover    = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);\n    toggle->userdata        = nk_handle_ptr(0);\n    toggle->text_background = table[NK_COLOR_WINDOW];\n    toggle->text_normal     = table[NK_COLOR_TEXT];\n    toggle->text_hover      = table[NK_COLOR_TEXT];\n    toggle->text_active     = table[NK_COLOR_TEXT];\n    toggle->padding         = nk_vec2(3.0f, 3.0f);\n    toggle->touch_padding   = nk_vec2(0,0);\n    toggle->border_color    = nk_rgba(0,0,0,0);\n    toggle->border          = 0.0f;\n    toggle->spacing         = 4;\n    toggle->color_factor    = 1.0f;\n    toggle->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n\n    /* selectable */\n    select = &style->selectable;\n    nk_zero_struct(*select);\n    select->normal          = nk_style_item_color(table[NK_COLOR_SELECT]);\n    select->hover           = nk_style_item_color(table[NK_COLOR_SELECT]);\n    select->pressed         = nk_style_item_color(table[NK_COLOR_SELECT]);\n    select->normal_active   = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);\n    select->hover_active    = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);\n    select->pressed_active  = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);\n    select->text_normal     = table[NK_COLOR_TEXT];\n    select->text_hover      = table[NK_COLOR_TEXT];\n    select->text_pressed    = table[NK_COLOR_TEXT];\n    select->text_normal_active  = table[NK_COLOR_TEXT];\n    select->text_hover_active   = table[NK_COLOR_TEXT];\n    select->text_pressed_active = table[NK_COLOR_TEXT];\n    select->padding         = nk_vec2(2.0f,2.0f);\n    select->image_padding   = nk_vec2(2.0f,2.0f);\n    select->touch_padding   = nk_vec2(0,0);\n    select->userdata        = nk_handle_ptr(0);\n    select->rounding        = 0.0f;\n    select->color_factor    = 1.0f;\n    select->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    select->draw_begin      = 0;\n    select->draw_end        = 0;\n\n    /* slider */\n    slider = &style->slider;\n    nk_zero_struct(*slider);\n    slider->normal          = nk_style_item_hide();\n    slider->hover           = nk_style_item_hide();\n    slider->active          = nk_style_item_hide();\n    slider->bar_normal      = table[NK_COLOR_SLIDER];\n    slider->bar_hover       = table[NK_COLOR_SLIDER];\n    slider->bar_active      = table[NK_COLOR_SLIDER];\n    slider->bar_filled      = table[NK_COLOR_SLIDER_CURSOR];\n    slider->cursor_normal   = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]);\n    slider->cursor_hover    = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]);\n    slider->cursor_active   = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]);\n    slider->inc_symbol      = NK_SYMBOL_TRIANGLE_RIGHT;\n    slider->dec_symbol      = NK_SYMBOL_TRIANGLE_LEFT;\n    slider->cursor_size     = nk_vec2(16,16);\n    slider->padding         = nk_vec2(2,2);\n    slider->spacing         = nk_vec2(2,2);\n    slider->userdata        = nk_handle_ptr(0);\n    slider->show_buttons    = nk_false;\n    slider->bar_height      = 8;\n    slider->rounding        = 0;\n    slider->color_factor    = 1.0f;\n    slider->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    slider->draw_begin      = 0;\n    slider->draw_end        = 0;\n\n    /* slider buttons */\n    button = &style->slider.inc_button;\n    button->normal          = nk_style_item_color(nk_rgb(40,40,40));\n    button->hover           = nk_style_item_color(nk_rgb(42,42,42));\n    button->active          = nk_style_item_color(nk_rgb(44,44,44));\n    button->border_color    = nk_rgb(65,65,65);\n    button->text_background = nk_rgb(40,40,40);\n    button->text_normal     = nk_rgb(175,175,175);\n    button->text_hover      = nk_rgb(175,175,175);\n    button->text_active     = nk_rgb(175,175,175);\n    button->padding         = nk_vec2(8.0f,8.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 1.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n    style->slider.dec_button = style->slider.inc_button;\n\n    /* knob */\n    knob = &style->knob;\n    nk_zero_struct(*knob);\n    knob->normal          = nk_style_item_hide();\n    knob->hover           = nk_style_item_hide();\n    knob->active          = nk_style_item_hide();\n    knob->knob_normal     = table[NK_COLOR_KNOB];\n    knob->knob_hover      = table[NK_COLOR_KNOB];\n    knob->knob_active     = table[NK_COLOR_KNOB];\n    knob->cursor_normal   = table[NK_COLOR_KNOB_CURSOR];\n    knob->cursor_hover    = table[NK_COLOR_KNOB_CURSOR_HOVER];\n    knob->cursor_active   = table[NK_COLOR_KNOB_CURSOR_ACTIVE];\n\n    knob->knob_border_color = table[NK_COLOR_BORDER];\n    knob->knob_border       = 1.0f;\n\n    knob->padding         = nk_vec2(2,2);\n    knob->spacing         = nk_vec2(2,2);\n    knob->cursor_width    = 2;\n    knob->color_factor    = 1.0f;\n    knob->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n\n    knob->userdata        = nk_handle_ptr(0);\n    knob->draw_begin      = 0;\n    knob->draw_end        = 0;\n\n    /* progressbar */\n    prog = &style->progress;\n    nk_zero_struct(*prog);\n    prog->normal            = nk_style_item_color(table[NK_COLOR_SLIDER]);\n    prog->hover             = nk_style_item_color(table[NK_COLOR_SLIDER]);\n    prog->active            = nk_style_item_color(table[NK_COLOR_SLIDER]);\n    prog->cursor_normal     = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]);\n    prog->cursor_hover      = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]);\n    prog->cursor_active     = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]);\n    prog->border_color      = nk_rgba(0,0,0,0);\n    prog->cursor_border_color = nk_rgba(0,0,0,0);\n    prog->userdata          = nk_handle_ptr(0);\n    prog->padding           = nk_vec2(4,4);\n    prog->rounding          = 0;\n    prog->border            = 0;\n    prog->cursor_rounding   = 0;\n    prog->cursor_border     = 0;\n    prog->color_factor      = 1.0f;\n    prog->disabled_factor   = NK_WIDGET_DISABLED_FACTOR;\n    prog->draw_begin        = 0;\n    prog->draw_end          = 0;\n\n    /* scrollbars */\n    scroll = &style->scrollh;\n    nk_zero_struct(*scroll);\n    scroll->normal          = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);\n    scroll->hover           = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);\n    scroll->active          = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);\n    scroll->cursor_normal   = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR]);\n    scroll->cursor_hover    = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_HOVER]);\n    scroll->cursor_active   = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE]);\n    scroll->dec_symbol      = NK_SYMBOL_CIRCLE_SOLID;\n    scroll->inc_symbol      = NK_SYMBOL_CIRCLE_SOLID;\n    scroll->userdata        = nk_handle_ptr(0);\n    scroll->border_color    = table[NK_COLOR_SCROLLBAR];\n    scroll->cursor_border_color = table[NK_COLOR_SCROLLBAR];\n    scroll->padding         = nk_vec2(0,0);\n    scroll->show_buttons    = nk_false;\n    scroll->border          = 0;\n    scroll->rounding        = 0;\n    scroll->border_cursor   = 0;\n    scroll->rounding_cursor = 0;\n    scroll->color_factor    = 1.0f;\n    scroll->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    scroll->draw_begin      = 0;\n    scroll->draw_end        = 0;\n    style->scrollv = style->scrollh;\n\n    /* scrollbars buttons */\n    button = &style->scrollh.inc_button;\n    button->normal          = nk_style_item_color(nk_rgb(40,40,40));\n    button->hover           = nk_style_item_color(nk_rgb(42,42,42));\n    button->active          = nk_style_item_color(nk_rgb(44,44,44));\n    button->border_color    = nk_rgb(65,65,65);\n    button->text_background = nk_rgb(40,40,40);\n    button->text_normal     = nk_rgb(175,175,175);\n    button->text_hover      = nk_rgb(175,175,175);\n    button->text_active     = nk_rgb(175,175,175);\n    button->padding         = nk_vec2(4.0f,4.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 1.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n    style->scrollh.dec_button = style->scrollh.inc_button;\n    style->scrollv.inc_button = style->scrollh.inc_button;\n    style->scrollv.dec_button = style->scrollh.inc_button;\n\n    /* edit */\n    edit = &style->edit;\n    nk_zero_struct(*edit);\n    edit->normal            = nk_style_item_color(table[NK_COLOR_EDIT]);\n    edit->hover             = nk_style_item_color(table[NK_COLOR_EDIT]);\n    edit->active            = nk_style_item_color(table[NK_COLOR_EDIT]);\n    edit->cursor_normal     = table[NK_COLOR_TEXT];\n    edit->cursor_hover      = table[NK_COLOR_TEXT];\n    edit->cursor_text_normal= table[NK_COLOR_EDIT];\n    edit->cursor_text_hover = table[NK_COLOR_EDIT];\n    edit->border_color      = table[NK_COLOR_BORDER];\n    edit->text_normal       = table[NK_COLOR_TEXT];\n    edit->text_hover        = table[NK_COLOR_TEXT];\n    edit->text_active       = table[NK_COLOR_TEXT];\n    edit->selected_normal   = table[NK_COLOR_TEXT];\n    edit->selected_hover    = table[NK_COLOR_TEXT];\n    edit->selected_text_normal  = table[NK_COLOR_EDIT];\n    edit->selected_text_hover   = table[NK_COLOR_EDIT];\n    edit->scrollbar_size    = nk_vec2(10,10);\n    edit->scrollbar         = style->scrollv;\n    edit->padding           = nk_vec2(4,4);\n    edit->row_padding       = 2;\n    edit->cursor_size       = 4;\n    edit->border            = 1;\n    edit->rounding          = 0;\n    edit->color_factor      = 1.0f;\n    edit->disabled_factor   = NK_WIDGET_DISABLED_FACTOR;\n\n    /* property */\n    property = &style->property;\n    nk_zero_struct(*property);\n    property->normal        = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    property->hover         = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    property->active        = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    property->border_color  = table[NK_COLOR_BORDER];\n    property->label_normal  = table[NK_COLOR_TEXT];\n    property->label_hover   = table[NK_COLOR_TEXT];\n    property->label_active  = table[NK_COLOR_TEXT];\n    property->sym_left      = NK_SYMBOL_TRIANGLE_LEFT;\n    property->sym_right     = NK_SYMBOL_TRIANGLE_RIGHT;\n    property->userdata      = nk_handle_ptr(0);\n    property->padding       = nk_vec2(4,4);\n    property->border        = 1;\n    property->rounding      = 10;\n    property->draw_begin    = 0;\n    property->draw_end      = 0;\n    property->color_factor  = 1.0f;\n    property->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n\n    /* property buttons */\n    button = &style->property.dec_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    button->active          = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    button->border_color    = nk_rgba(0,0,0,0);\n    button->text_background = table[NK_COLOR_PROPERTY];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(0.0f,0.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n    style->property.inc_button = style->property.dec_button;\n\n    /* property edit */\n    edit = &style->property.edit;\n    nk_zero_struct(*edit);\n    edit->normal            = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    edit->hover             = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    edit->active            = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    edit->border_color      = nk_rgba(0,0,0,0);\n    edit->cursor_normal     = table[NK_COLOR_TEXT];\n    edit->cursor_hover      = table[NK_COLOR_TEXT];\n    edit->cursor_text_normal= table[NK_COLOR_EDIT];\n    edit->cursor_text_hover = table[NK_COLOR_EDIT];\n    edit->text_normal       = table[NK_COLOR_TEXT];\n    edit->text_hover        = table[NK_COLOR_TEXT];\n    edit->text_active       = table[NK_COLOR_TEXT];\n    edit->selected_normal   = table[NK_COLOR_TEXT];\n    edit->selected_hover    = table[NK_COLOR_TEXT];\n    edit->selected_text_normal  = table[NK_COLOR_EDIT];\n    edit->selected_text_hover   = table[NK_COLOR_EDIT];\n    edit->padding           = nk_vec2(0,0);\n    edit->cursor_size       = 8;\n    edit->border            = 0;\n    edit->rounding          = 0;\n    edit->color_factor      = 1.0f;\n    edit->disabled_factor   = NK_WIDGET_DISABLED_FACTOR;\n\n    /* chart */\n    chart = &style->chart;\n    nk_zero_struct(*chart);\n    chart->background       = nk_style_item_color(table[NK_COLOR_CHART]);\n    chart->border_color     = table[NK_COLOR_BORDER];\n    chart->selected_color   = table[NK_COLOR_CHART_COLOR_HIGHLIGHT];\n    chart->color            = table[NK_COLOR_CHART_COLOR];\n    chart->padding          = nk_vec2(4,4);\n    chart->border           = 0;\n    chart->rounding         = 0;\n    chart->color_factor     = 1.0f;\n    chart->disabled_factor  = NK_WIDGET_DISABLED_FACTOR;\n    chart->show_markers     = nk_true;\n\n    /* combo */\n    combo = &style->combo;\n    combo->normal           = nk_style_item_color(table[NK_COLOR_COMBO]);\n    combo->hover            = nk_style_item_color(table[NK_COLOR_COMBO]);\n    combo->active           = nk_style_item_color(table[NK_COLOR_COMBO]);\n    combo->border_color     = table[NK_COLOR_BORDER];\n    combo->label_normal     = table[NK_COLOR_TEXT];\n    combo->label_hover      = table[NK_COLOR_TEXT];\n    combo->label_active     = table[NK_COLOR_TEXT];\n    combo->sym_normal       = NK_SYMBOL_TRIANGLE_DOWN;\n    combo->sym_hover        = NK_SYMBOL_TRIANGLE_DOWN;\n    combo->sym_active       = NK_SYMBOL_TRIANGLE_DOWN;\n    combo->content_padding  = nk_vec2(4,4);\n    combo->button_padding   = nk_vec2(0,4);\n    combo->spacing          = nk_vec2(4,0);\n    combo->border           = 1;\n    combo->rounding         = 0;\n    combo->color_factor     = 1.0f;\n    combo->disabled_factor  = NK_WIDGET_DISABLED_FACTOR;\n\n    /* combo button */\n    button = &style->combo.button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_COMBO]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_COMBO]);\n    button->active          = nk_style_item_color(table[NK_COLOR_COMBO]);\n    button->border_color    = nk_rgba(0,0,0,0);\n    button->text_background = table[NK_COLOR_COMBO];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(2.0f,2.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n\n    /* tab */\n    tab = &style->tab;\n    tab->background         = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);\n    tab->border_color       = table[NK_COLOR_BORDER];\n    tab->text               = table[NK_COLOR_TEXT];\n    tab->sym_minimize       = NK_SYMBOL_TRIANGLE_RIGHT;\n    tab->sym_maximize       = NK_SYMBOL_TRIANGLE_DOWN;\n    tab->padding            = nk_vec2(4,4);\n    tab->spacing            = nk_vec2(4,4);\n    tab->indent             = 10.0f;\n    tab->border             = 1;\n    tab->rounding           = 0;\n    tab->color_factor       = 1.0f;\n    tab->disabled_factor    = NK_WIDGET_DISABLED_FACTOR;\n\n    /* tab button */\n    button = &style->tab.tab_minimize_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);\n    button->active          = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);\n    button->border_color    = nk_rgba(0,0,0,0);\n    button->text_background = table[NK_COLOR_TAB_HEADER];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(2.0f,2.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n    style->tab.tab_maximize_button =*button;\n\n    /* node button */\n    button = &style->tab.node_minimize_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->active          = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->border_color    = nk_rgba(0,0,0,0);\n    button->text_background = table[NK_COLOR_TAB_HEADER];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(2.0f,2.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n    style->tab.node_maximize_button =*button;\n\n    /* window header */\n    win = &style->window;\n    win->header.align = NK_HEADER_RIGHT;\n    win->header.close_symbol = NK_SYMBOL_X;\n    win->header.minimize_symbol = NK_SYMBOL_MINUS;\n    win->header.maximize_symbol = NK_SYMBOL_PLUS;\n    win->header.normal = nk_style_item_color(table[NK_COLOR_HEADER]);\n    win->header.hover = nk_style_item_color(table[NK_COLOR_HEADER]);\n    win->header.active = nk_style_item_color(table[NK_COLOR_HEADER]);\n    win->header.label_normal = table[NK_COLOR_TEXT];\n    win->header.label_hover = table[NK_COLOR_TEXT];\n    win->header.label_active = table[NK_COLOR_TEXT];\n    win->header.label_padding = nk_vec2(4,4);\n    win->header.padding = nk_vec2(4,4);\n    win->header.spacing = nk_vec2(0,0);\n\n    /* window header close button */\n    button = &style->window.header.close_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_HEADER]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_HEADER]);\n    button->active          = nk_style_item_color(table[NK_COLOR_HEADER]);\n    button->border_color    = nk_rgba(0,0,0,0);\n    button->text_background = table[NK_COLOR_HEADER];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(0.0f,0.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n\n    /* window header minimize button */\n    button = &style->window.header.minimize_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_HEADER]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_HEADER]);\n    button->active          = nk_style_item_color(table[NK_COLOR_HEADER]);\n    button->border_color    = nk_rgba(0,0,0,0);\n    button->text_background = table[NK_COLOR_HEADER];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(0.0f,0.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n\n    /* window */\n    win->background = table[NK_COLOR_WINDOW];\n    win->fixed_background = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    win->border_color = table[NK_COLOR_BORDER];\n    win->popup_border_color = table[NK_COLOR_BORDER];\n    win->combo_border_color = table[NK_COLOR_BORDER];\n    win->contextual_border_color = table[NK_COLOR_BORDER];\n    win->menu_border_color = table[NK_COLOR_BORDER];\n    win->group_border_color = table[NK_COLOR_BORDER];\n    win->tooltip_border_color = table[NK_COLOR_BORDER];\n    win->scaler = nk_style_item_color(table[NK_COLOR_TEXT]);\n\n    win->rounding = 0.0f;\n    win->spacing = nk_vec2(4,4);\n    win->scrollbar_size = nk_vec2(10,10);\n    win->min_size = nk_vec2(64,64);\n\n    win->combo_border = 1.0f;\n    win->contextual_border = 1.0f;\n    win->menu_border = 1.0f;\n    win->group_border = 1.0f;\n    win->tooltip_border = 1.0f;\n    win->popup_border = 1.0f;\n    win->border = 2.0f;\n    win->min_row_height_padding = 8;\n\n    win->padding = nk_vec2(4,4);\n    win->group_padding = nk_vec2(4,4);\n    win->popup_padding = nk_vec2(4,4);\n    win->combo_padding = nk_vec2(4,4);\n    win->contextual_padding = nk_vec2(4,4);\n    win->menu_padding = nk_vec2(4,4);\n    win->tooltip_padding = nk_vec2(4,4);\n\n    /* default tooltip just down and to the right of the cursor\n     * so it doesn't cover the text\n     *\n     * TODO might be worth consolidating tooltip styling\n     * into its own style structure, though it is a\n     * type of window...*/\n    win->tooltip_origin = NK_TOP_LEFT;\n    win->tooltip_offset = nk_vec2(12, 12);\n}\nNK_API void\nnk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font)\n{\n    struct nk_style *style;\n    NK_ASSERT(ctx);\n\n    if (!ctx) return;\n    style = &ctx->style;\n    style->font = font;\n    ctx->stacks.fonts.head = 0;\n    if (ctx->current)\n        nk_layout_reset_min_row_height(ctx);\n}\nNK_API nk_bool\nnk_style_push_font(struct nk_context *ctx, const struct nk_user_font *font)\n{\n    struct nk_config_stack_user_font *font_stack;\n    struct nk_config_stack_user_font_element *element;\n\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n\n    font_stack = &ctx->stacks.fonts;\n    NK_ASSERT(font_stack->head < (int)NK_LEN(font_stack->elements));\n    if (font_stack->head >= (int)NK_LEN(font_stack->elements))\n        return 0;\n\n    element = &font_stack->elements[font_stack->head++];\n    element->address = &ctx->style.font;\n    element->old_value = ctx->style.font;\n    ctx->style.font = font;\n    return 1;\n}\nNK_API nk_bool\nnk_style_pop_font(struct nk_context *ctx)\n{\n    struct nk_config_stack_user_font *font_stack;\n    struct nk_config_stack_user_font_element *element;\n\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n\n    font_stack = &ctx->stacks.fonts;\n    NK_ASSERT(font_stack->head > 0);\n    if (font_stack->head < 1)\n        return 0;\n\n    element = &font_stack->elements[--font_stack->head];\n    *element->address = element->old_value;\n    return 1;\n}\n#define NK_STYLE_PUSH_IMPLEMENATION(prefix, type, stack) \\\nnk_style_push_##type(struct nk_context *ctx, prefix##_##type *address, prefix##_##type value)\\\n{\\\n    struct nk_config_stack_##type * type_stack;\\\n    struct nk_config_stack_##type##_element *element;\\\n    NK_ASSERT(ctx);\\\n    if (!ctx) return 0;\\\n    type_stack = &ctx->stacks.stack;\\\n    NK_ASSERT(type_stack->head < (int)NK_LEN(type_stack->elements));\\\n    if (type_stack->head >= (int)NK_LEN(type_stack->elements))\\\n        return 0;\\\n    element = &type_stack->elements[type_stack->head++];\\\n    element->address = address;\\\n    element->old_value = *address;\\\n    *address = value;\\\n    return 1;\\\n}\n#define NK_STYLE_POP_IMPLEMENATION(type, stack) \\\nnk_style_pop_##type(struct nk_context *ctx)\\\n{\\\n    struct nk_config_stack_##type *type_stack;\\\n    struct nk_config_stack_##type##_element *element;\\\n    NK_ASSERT(ctx);\\\n    if (!ctx) return 0;\\\n    type_stack = &ctx->stacks.stack;\\\n    NK_ASSERT(type_stack->head > 0);\\\n    if (type_stack->head < 1)\\\n        return 0;\\\n    element = &type_stack->elements[--type_stack->head];\\\n    *element->address = element->old_value;\\\n    return 1;\\\n}\nNK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk, style_item, style_items)\nNK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(nk,float, floats)\nNK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk, vec2, vectors)\nNK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(nk,flags, flags)\nNK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk,color, colors)\n\nNK_API nk_bool NK_STYLE_POP_IMPLEMENATION(style_item, style_items)\nNK_API nk_bool NK_STYLE_POP_IMPLEMENATION(float,floats)\nNK_API nk_bool NK_STYLE_POP_IMPLEMENATION(vec2, vectors)\nNK_API nk_bool NK_STYLE_POP_IMPLEMENATION(flags,flags)\nNK_API nk_bool NK_STYLE_POP_IMPLEMENATION(color,colors)\n\nNK_API nk_bool\nnk_style_set_cursor(struct nk_context *ctx, enum nk_style_cursor c)\n{\n    struct nk_style *style;\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    style = &ctx->style;\n    if (style->cursors[c]) {\n        style->cursor_active = style->cursors[c];\n        return 1;\n    }\n    return 0;\n}\nNK_API void\nnk_style_show_cursor(struct nk_context *ctx)\n{\n    ctx->style.cursor_visible = nk_true;\n}\nNK_API void\nnk_style_hide_cursor(struct nk_context *ctx)\n{\n    ctx->style.cursor_visible = nk_false;\n}\nNK_API void\nnk_style_load_cursor(struct nk_context *ctx, enum nk_style_cursor cursor,\n    const struct nk_cursor *c)\n{\n    struct nk_style *style;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    style = &ctx->style;\n    style->cursors[cursor] = c;\n}\nNK_API void\nnk_style_load_all_cursors(struct nk_context *ctx, const struct nk_cursor *cursors)\n{\n    int i = 0;\n    struct nk_style *style;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    style = &ctx->style;\n    for (i = 0; i < NK_CURSOR_COUNT; ++i)\n        style->cursors[i] = &cursors[i];\n    style->cursor_visible = nk_true;\n}\n\n\n\n\n/* ==============================================================\n *\n *                          CONTEXT\n *\n * ===============================================================*/\nNK_INTERN void\nnk_setup(struct nk_context *ctx, const struct nk_user_font *font)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    nk_zero_struct(*ctx);\n    nk_style_default(ctx);\n    ctx->seq = 1;\n    if (font) ctx->style.font = font;\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n    nk_draw_list_init(&ctx->draw_list);\n#endif\n}\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API nk_bool\nnk_init_default(struct nk_context *ctx, const struct nk_user_font *font)\n{\n    struct nk_allocator alloc;\n    alloc.userdata.ptr = 0;\n    alloc.alloc = nk_malloc;\n    alloc.free = nk_mfree;\n    return nk_init(ctx, &alloc, font);\n}\n#endif\nNK_API nk_bool\nnk_init_fixed(struct nk_context *ctx, void *memory, nk_size size,\n    const struct nk_user_font *font)\n{\n    NK_ASSERT(memory);\n    if (!memory) return 0;\n    nk_setup(ctx, font);\n    nk_buffer_init_fixed(&ctx->memory, memory, size);\n    ctx->use_pool = nk_false;\n    return 1;\n}\nNK_API nk_bool\nnk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds,\n    struct nk_buffer *pool, const struct nk_user_font *font)\n{\n    NK_ASSERT(cmds);\n    NK_ASSERT(pool);\n    if (!cmds || !pool) return 0;\n\n    nk_setup(ctx, font);\n    ctx->memory = *cmds;\n    if (pool->type == NK_BUFFER_FIXED) {\n        /* take memory from buffer and alloc fixed pool */\n        nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size);\n    } else {\n        /* create dynamic pool from buffer allocator */\n        struct nk_allocator *alloc = &pool->pool;\n        nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);\n    }\n    ctx->use_pool = nk_true;\n    return 1;\n}\nNK_API nk_bool\nnk_init(struct nk_context *ctx, const struct nk_allocator *alloc,\n    const struct nk_user_font *font)\n{\n    NK_ASSERT(alloc);\n    if (!alloc) return 0;\n    nk_setup(ctx, font);\n    nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE);\n    nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);\n    ctx->use_pool = nk_true;\n    return 1;\n}\n#ifdef NK_INCLUDE_COMMAND_USERDATA\nNK_API void\nnk_set_user_data(struct nk_context *ctx, nk_handle handle)\n{\n    if (!ctx) return;\n    ctx->userdata = handle;\n    if (ctx->current)\n        ctx->current->buffer.userdata = handle;\n}\n#endif\nNK_API void\nnk_free(struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    nk_buffer_free(&ctx->memory);\n    if (ctx->use_pool)\n        nk_pool_free(&ctx->pool);\n\n    nk_zero(&ctx->input, sizeof(ctx->input));\n    nk_zero(&ctx->style, sizeof(ctx->style));\n    nk_zero(&ctx->memory, sizeof(ctx->memory));\n\n    ctx->seq = 0;\n    ctx->build = 0;\n    ctx->begin = 0;\n    ctx->end = 0;\n    ctx->active = 0;\n    ctx->current = 0;\n    ctx->freelist = 0;\n    ctx->count = 0;\n}\nNK_API void\nnk_clear(struct nk_context *ctx)\n{\n    struct nk_window *iter;\n    struct nk_window *next;\n    NK_ASSERT(ctx);\n\n    if (!ctx) return;\n    if (ctx->use_pool)\n        nk_buffer_clear(&ctx->memory);\n    else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT);\n\n    ctx->build = 0;\n    ctx->memory.calls = 0;\n    ctx->last_widget_state = 0;\n    ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];\n    NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay));\n\n    /* garbage collector */\n    iter = ctx->begin;\n    while (iter) {\n        /* make sure valid minimized windows do not get removed */\n        if ((iter->flags & NK_WINDOW_MINIMIZED) &&\n            !(iter->flags & NK_WINDOW_CLOSED) &&\n            iter->seq == ctx->seq) {\n            iter = iter->next;\n            continue;\n        }\n        /* remove hotness from hidden or closed windows*/\n        if (((iter->flags & NK_WINDOW_HIDDEN) ||\n            (iter->flags & NK_WINDOW_CLOSED)) &&\n            iter == ctx->active) {\n            ctx->active = iter->prev;\n            ctx->end = iter->prev;\n            if (!ctx->end)\n                ctx->begin = 0;\n            if (ctx->active)\n                ctx->active->flags &= ~(unsigned)NK_WINDOW_ROM;\n        }\n        /* free unused popup windows */\n        if (iter->popup.win && iter->popup.win->seq != ctx->seq) {\n            nk_free_window(ctx, iter->popup.win);\n            iter->popup.win = 0;\n        }\n        /* remove unused window state tables */\n        {struct nk_table *n, *it = iter->tables;\n        while (it) {\n            n = it->next;\n            if (it->seq != ctx->seq) {\n                nk_remove_table(iter, it);\n                nk_zero(it, sizeof(union nk_page_data));\n                nk_free_table(ctx, it);\n                if (it == iter->tables)\n                    iter->tables = n;\n            } it = n;\n        }}\n        /* window itself is not used anymore so free */\n        if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) {\n            next = iter->next;\n            nk_remove_window(ctx, iter);\n            nk_free_window(ctx, iter);\n            iter = next;\n        } else iter = iter->next;\n    }\n    ctx->seq++;\n}\nNK_LIB void\nnk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(buffer);\n    if (!ctx || !buffer) return;\n    buffer->begin = ctx->memory.allocated;\n    buffer->end = buffer->begin;\n    buffer->last = buffer->begin;\n    buffer->clip = nk_null_rect;\n}\nNK_LIB void\nnk_start(struct nk_context *ctx, struct nk_window *win)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(win);\n    nk_start_buffer(ctx, &win->buffer);\n}\nNK_LIB void\nnk_start_popup(struct nk_context *ctx, struct nk_window *win)\n{\n    struct nk_popup_buffer *buf;\n    NK_ASSERT(ctx);\n    NK_ASSERT(win);\n    if (!ctx || !win) return;\n\n    /* save buffer fill state for popup */\n    buf = &win->popup.buf;\n    buf->begin = win->buffer.end;\n    buf->end = win->buffer.end;\n    buf->parent = win->buffer.last;\n    buf->last = buf->begin;\n    buf->active = nk_true;\n}\nNK_LIB void\nnk_finish_popup(struct nk_context *ctx, struct nk_window *win)\n{\n    struct nk_popup_buffer *buf;\n    NK_ASSERT(ctx);\n    NK_ASSERT(win);\n    if (!ctx || !win) return;\n\n    buf = &win->popup.buf;\n    buf->last = win->buffer.last;\n    buf->end = win->buffer.end;\n}\nNK_LIB void\nnk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(buffer);\n    if (!ctx || !buffer) return;\n    buffer->end = ctx->memory.allocated;\n}\nNK_LIB void\nnk_finish(struct nk_context *ctx, struct nk_window *win)\n{\n    struct nk_popup_buffer *buf;\n    struct nk_command *parent_last;\n    void *memory;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(win);\n    if (!ctx || !win) return;\n    nk_finish_buffer(ctx, &win->buffer);\n    if (!win->popup.buf.active) return;\n\n    buf = &win->popup.buf;\n    memory = ctx->memory.memory.ptr;\n    parent_last = nk_ptr_add(struct nk_command, memory, buf->parent);\n    parent_last->next = buf->end;\n}\nNK_LIB void\nnk_build(struct nk_context *ctx)\n{\n    struct nk_window *it = 0;\n    struct nk_command *cmd = 0;\n    nk_byte *buffer = 0;\n\n    /* draw cursor overlay */\n    if (!ctx->style.cursor_active)\n        ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];\n    if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) {\n        struct nk_rect mouse_bounds;\n        const struct nk_cursor *cursor = ctx->style.cursor_active;\n        nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF);\n        nk_start_buffer(ctx, &ctx->overlay);\n\n        mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x;\n        mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y;\n        mouse_bounds.w = cursor->size.x;\n        mouse_bounds.h = cursor->size.y;\n\n        nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white);\n        nk_finish_buffer(ctx, &ctx->overlay);\n    }\n    /* build one big draw command list out of all window buffers */\n    it = ctx->begin;\n    buffer = (nk_byte*)ctx->memory.memory.ptr;\n    while (it != 0) {\n        struct nk_window *next = it->next;\n        if (it->buffer.last == it->buffer.begin || (it->flags & NK_WINDOW_HIDDEN)||\n            it->seq != ctx->seq)\n            goto cont;\n\n        cmd = nk_ptr_add(struct nk_command, buffer, it->buffer.last);\n        while (next && ((next->buffer.last == next->buffer.begin) ||\n            (next->flags & NK_WINDOW_HIDDEN) || next->seq != ctx->seq))\n            next = next->next; /* skip empty command buffers */\n\n        if (next) cmd->next = next->buffer.begin;\n        cont: it = next;\n    }\n    /* append all popup draw commands into lists */\n    it = ctx->begin;\n    while (it != 0) {\n        struct nk_window *next = it->next;\n        struct nk_popup_buffer *buf;\n        if (!it->popup.buf.active)\n            goto skip;\n\n        buf = &it->popup.buf;\n        cmd->next = buf->begin;\n        cmd = nk_ptr_add(struct nk_command, buffer, buf->last);\n        buf->active = nk_false;\n        skip: it = next;\n    }\n    if (cmd) {\n        /* append overlay commands */\n        if (ctx->overlay.end != ctx->overlay.begin)\n            cmd->next = ctx->overlay.begin;\n        else cmd->next = ctx->memory.allocated;\n    }\n}\nNK_API const struct nk_command*\nnk__begin(struct nk_context *ctx)\n{\n    struct nk_window *iter;\n    nk_byte *buffer;\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    if (!ctx->count) return 0;\n\n    buffer = (nk_byte*)ctx->memory.memory.ptr;\n    if (!ctx->build) {\n        nk_build(ctx);\n        ctx->build = nk_true;\n    }\n    iter = ctx->begin;\n    while (iter && ((iter->buffer.begin == iter->buffer.end) ||\n        (iter->flags & NK_WINDOW_HIDDEN) || iter->seq != ctx->seq))\n        iter = iter->next;\n    if (!iter) return 0;\n    return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin);\n}\n\nNK_API const struct nk_command*\nnk__next(struct nk_context *ctx, const struct nk_command *cmd)\n{\n    nk_byte *buffer;\n    const struct nk_command *next;\n    NK_ASSERT(ctx);\n    if (!ctx || !cmd || !ctx->count) return 0;\n    if (cmd->next >= ctx->memory.allocated) return 0;\n    buffer = (nk_byte*)ctx->memory.memory.ptr;\n    next = nk_ptr_add_const(struct nk_command, buffer, cmd->next);\n    return next;\n}\n\n\n\n\n\n\n/* ===============================================================\n *\n *                              POOL\n *\n * ===============================================================*/\nNK_LIB void\nnk_pool_init(struct nk_pool *pool, const struct nk_allocator *alloc,\n    unsigned int capacity)\n{\n    NK_ASSERT(capacity >= 1);\n    nk_zero(pool, sizeof(*pool));\n    pool->alloc = *alloc;\n    pool->capacity = capacity;\n    pool->type = NK_BUFFER_DYNAMIC;\n    pool->pages = 0;\n}\nNK_LIB void\nnk_pool_free(struct nk_pool *pool)\n{\n    struct nk_page *iter;\n    if (!pool) return;\n    iter = pool->pages;\n    if (pool->type == NK_BUFFER_FIXED) return;\n    while (iter) {\n        struct nk_page *next = iter->next;\n        pool->alloc.free(pool->alloc.userdata, iter);\n        iter = next;\n    }\n}\nNK_LIB void\nnk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size)\n{\n    nk_zero(pool, sizeof(*pool));\n    NK_ASSERT(size >= sizeof(struct nk_page));\n    if (size < sizeof(struct nk_page)) return;\n    /* first nk_page_element is embedded in nk_page, additional elements follow in adjacent space */\n    pool->capacity = (unsigned)(1 + (size - sizeof(struct nk_page)) / sizeof(struct nk_page_element));\n    pool->pages = (struct nk_page*)memory;\n    pool->type = NK_BUFFER_FIXED;\n    pool->size = size;\n}\nNK_LIB struct nk_page_element*\nnk_pool_alloc(struct nk_pool *pool)\n{\n    if (!pool->pages || pool->pages->size >= pool->capacity) {\n        /* allocate new page */\n        struct nk_page *page;\n        if (pool->type == NK_BUFFER_FIXED) {\n            NK_ASSERT(pool->pages);\n            if (!pool->pages) return 0;\n            NK_ASSERT(pool->pages->size < pool->capacity);\n            return 0;\n        } else {\n            nk_size size = sizeof(struct nk_page);\n            size += (pool->capacity - 1) * sizeof(struct nk_page_element);\n            page = (struct nk_page*)pool->alloc.alloc(pool->alloc.userdata,0, size);\n            page->next = pool->pages;\n            pool->pages = page;\n            page->size = 0;\n        }\n    } return &pool->pages->win[pool->pages->size++];\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                          PAGE ELEMENT\n *\n * ===============================================================*/\nNK_LIB struct nk_page_element*\nnk_create_page_element(struct nk_context *ctx)\n{\n    struct nk_page_element *elem;\n    if (ctx->freelist) {\n        /* unlink page element from free list */\n        elem = ctx->freelist;\n        ctx->freelist = elem->next;\n    } else if (ctx->use_pool) {\n        /* allocate page element from memory pool */\n        elem = nk_pool_alloc(&ctx->pool);\n        NK_ASSERT(elem);\n        if (!elem) return 0;\n    } else {\n        /* allocate new page element from back of fixed size memory buffer */\n        NK_STORAGE const nk_size size = sizeof(struct nk_page_element);\n        NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_page_element);\n        elem = (struct nk_page_element*)nk_buffer_alloc(&ctx->memory, NK_BUFFER_BACK, size, align);\n        NK_ASSERT(elem);\n        if (!elem) return 0;\n    }\n    nk_zero_struct(*elem);\n    elem->next = 0;\n    elem->prev = 0;\n    return elem;\n}\nNK_LIB void\nnk_link_page_element_into_freelist(struct nk_context *ctx,\n    struct nk_page_element *elem)\n{\n    /* link table into freelist */\n    if (!ctx->freelist) {\n        ctx->freelist = elem;\n    } else {\n        elem->next = ctx->freelist;\n        ctx->freelist = elem;\n    }\n}\nNK_LIB void\nnk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem)\n{\n    /* we have a pool so just add to free list */\n    if (ctx->use_pool) {\n        nk_link_page_element_into_freelist(ctx, elem);\n        return;\n    }\n    /* if possible remove last element from back of fixed memory buffer */\n    {void *elem_end = (void*)(elem + 1);\n    void *buffer_end = (nk_byte*)ctx->memory.memory.ptr + ctx->memory.size;\n    if (elem_end == buffer_end)\n        ctx->memory.size -= sizeof(struct nk_page_element);\n    else nk_link_page_element_into_freelist(ctx, elem);}\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                              TABLE\n *\n * ===============================================================*/\nNK_LIB struct nk_table*\nnk_create_table(struct nk_context *ctx)\n{\n    struct nk_page_element *elem;\n    elem = nk_create_page_element(ctx);\n    if (!elem) return 0;\n    return &elem->data.tbl;\n}\nNK_LIB void\nnk_free_table(struct nk_context *ctx, struct nk_table *tbl)\n{\n    union nk_page_data *pd = NK_CONTAINER_OF(tbl, union nk_page_data, tbl);\n    struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);\n    nk_free_page_element(ctx, pe);\n}\nNK_LIB void\nnk_push_table(struct nk_window *win, struct nk_table *tbl)\n{\n    if (!win->tables) {\n        win->tables = tbl;\n        tbl->next = 0;\n        tbl->prev = 0;\n        tbl->size = 0;\n        win->table_count = 1;\n        return;\n    }\n    win->tables->prev = tbl;\n    tbl->next = win->tables;\n    tbl->prev = 0;\n    tbl->size = 0;\n    win->tables = tbl;\n    win->table_count++;\n}\nNK_LIB void\nnk_remove_table(struct nk_window *win, struct nk_table *tbl)\n{\n    if (win->tables == tbl)\n        win->tables = tbl->next;\n    if (tbl->next)\n        tbl->next->prev = tbl->prev;\n    if (tbl->prev)\n        tbl->prev->next = tbl->next;\n    tbl->next = 0;\n    tbl->prev = 0;\n}\nNK_LIB nk_uint*\nnk_add_value(struct nk_context *ctx, struct nk_window *win,\n            nk_hash name, nk_uint value)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(win);\n    if (!win || !ctx) return 0;\n    if (!win->tables || win->tables->size >= NK_VALUE_PAGE_CAPACITY) {\n        struct nk_table *tbl = nk_create_table(ctx);\n        NK_ASSERT(tbl);\n        if (!tbl) return 0;\n        nk_push_table(win, tbl);\n    }\n    win->tables->seq = win->seq;\n    win->tables->keys[win->tables->size] = name;\n    win->tables->values[win->tables->size] = value;\n    return &win->tables->values[win->tables->size++];\n}\nNK_LIB nk_uint*\nnk_find_value(const struct nk_window *win, nk_hash name)\n{\n    struct nk_table *iter = win->tables;\n    while (iter) {\n        unsigned int i = 0;\n        unsigned int size = iter->size;\n        for (i = 0; i < size; ++i) {\n            if (iter->keys[i] == name) {\n                iter->seq = win->seq;\n                return &iter->values[i];\n            }\n        } size = NK_VALUE_PAGE_CAPACITY;\n        iter = iter->next;\n    }\n    return 0;\n}\n\n\n\n\n/* ===============================================================\n *\n *                              PANEL\n *\n * ===============================================================*/\nNK_LIB void*\nnk_create_panel(struct nk_context *ctx)\n{\n    struct nk_page_element *elem;\n    elem = nk_create_page_element(ctx);\n    if (!elem) return 0;\n    return &elem->data.pan;\n}\nNK_LIB void\nnk_free_panel(struct nk_context *ctx, struct nk_panel *pan)\n{\n    union nk_page_data *pd = NK_CONTAINER_OF(pan, union nk_page_data, pan);\n    struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);\n    nk_free_page_element(ctx, pe);\n}\nNK_LIB nk_bool\nnk_panel_has_header(nk_flags flags, const char *title)\n{\n    nk_bool active = 0;\n    active = (flags & (NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE));\n    active = active || (flags & NK_WINDOW_TITLE);\n    active = active && !(flags & NK_WINDOW_HIDDEN) && title;\n    return active;\n}\nNK_LIB struct nk_vec2\nnk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type)\n{\n    switch (type) {\n    default:\n    case NK_PANEL_WINDOW: return style->window.padding;\n    case NK_PANEL_GROUP: return style->window.group_padding;\n    case NK_PANEL_POPUP: return style->window.popup_padding;\n    case NK_PANEL_CONTEXTUAL: return style->window.contextual_padding;\n    case NK_PANEL_COMBO: return style->window.combo_padding;\n    case NK_PANEL_MENU: return style->window.menu_padding;\n    case NK_PANEL_TOOLTIP: return style->window.menu_padding;}\n}\nNK_LIB float\nnk_panel_get_border(const struct nk_style *style, nk_flags flags,\n    enum nk_panel_type type)\n{\n    if (flags & NK_WINDOW_BORDER) {\n        switch (type) {\n        default:\n        case NK_PANEL_WINDOW: return style->window.border;\n        case NK_PANEL_GROUP: return style->window.group_border;\n        case NK_PANEL_POPUP: return style->window.popup_border;\n        case NK_PANEL_CONTEXTUAL: return style->window.contextual_border;\n        case NK_PANEL_COMBO: return style->window.combo_border;\n        case NK_PANEL_MENU: return style->window.menu_border;\n        case NK_PANEL_TOOLTIP: return style->window.menu_border;\n    }} else return 0;\n}\nNK_LIB struct nk_color\nnk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type)\n{\n    switch (type) {\n    default:\n    case NK_PANEL_WINDOW: return style->window.border_color;\n    case NK_PANEL_GROUP: return style->window.group_border_color;\n    case NK_PANEL_POPUP: return style->window.popup_border_color;\n    case NK_PANEL_CONTEXTUAL: return style->window.contextual_border_color;\n    case NK_PANEL_COMBO: return style->window.combo_border_color;\n    case NK_PANEL_MENU: return style->window.menu_border_color;\n    case NK_PANEL_TOOLTIP: return style->window.menu_border_color;}\n}\nNK_LIB nk_bool\nnk_panel_is_sub(enum nk_panel_type type)\n{\n    return ((int)type & (int)NK_PANEL_SET_SUB)?1:0;\n}\nNK_LIB nk_bool\nnk_panel_is_nonblock(enum nk_panel_type type)\n{\n    return ((int)type & (int)NK_PANEL_SET_NONBLOCK)?1:0;\n}\nNK_LIB nk_bool\nnk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type)\n{\n    struct nk_input *in;\n    struct nk_window *win;\n    struct nk_panel *layout;\n    struct nk_command_buffer *out;\n    const struct nk_style *style;\n    const struct nk_user_font *font;\n\n    struct nk_vec2 scrollbar_size;\n    struct nk_vec2 panel_padding;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) return 0;\n    nk_zero(ctx->current->layout, sizeof(*ctx->current->layout));\n    if ((ctx->current->flags & NK_WINDOW_HIDDEN) || (ctx->current->flags & NK_WINDOW_CLOSED)) {\n        nk_zero(ctx->current->layout, sizeof(struct nk_panel));\n        ctx->current->layout->type = panel_type;\n        return 0;\n    }\n    /* pull state into local stack */\n    style = &ctx->style;\n    font = style->font;\n    win = ctx->current;\n    layout = win->layout;\n    out = &win->buffer;\n    in = (win->flags & NK_WINDOW_NO_INPUT) ? 0: &ctx->input;\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    win->buffer.userdata = ctx->userdata;\n#endif\n    /* pull style configuration into local stack */\n    scrollbar_size = style->window.scrollbar_size;\n    panel_padding = nk_panel_get_padding(style, panel_type);\n\n    /* window movement */\n    if ((win->flags & NK_WINDOW_MOVABLE) && !(win->flags & NK_WINDOW_ROM)) {\n        nk_bool left_mouse_down;\n        unsigned int left_mouse_clicked;\n        int left_mouse_click_in_cursor;\n\n        /* calculate draggable window space */\n        struct nk_rect header;\n        header.x = win->bounds.x;\n        header.y = win->bounds.y;\n        header.w = win->bounds.w;\n        if (nk_panel_has_header(win->flags, title)) {\n            header.h = font->height + 2.0f * style->window.header.padding.y;\n            header.h += 2.0f * style->window.header.label_padding.y;\n        } else header.h = panel_padding.y;\n\n        /* window movement by dragging */\n        left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;\n        left_mouse_clicked = in->mouse.buttons[NK_BUTTON_LEFT].clicked;\n        left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,\n            NK_BUTTON_LEFT, header, nk_true);\n        if (left_mouse_down && left_mouse_click_in_cursor && !left_mouse_clicked) {\n            win->bounds.x = win->bounds.x + in->mouse.delta.x;\n            win->bounds.y = win->bounds.y + in->mouse.delta.y;\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x += in->mouse.delta.x;\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y += in->mouse.delta.y;\n            ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_MOVE];\n        }\n    }\n\n    /* setup panel */\n    layout->type = panel_type;\n    layout->flags = win->flags;\n    layout->bounds = win->bounds;\n    layout->bounds.x += panel_padding.x;\n    layout->bounds.w -= 2*panel_padding.x;\n    if (win->flags & NK_WINDOW_BORDER) {\n        layout->border = nk_panel_get_border(style, win->flags, panel_type);\n        layout->bounds = nk_shrink_rect(layout->bounds, layout->border);\n    } else layout->border = 0;\n    layout->at_y = layout->bounds.y;\n    layout->at_x = layout->bounds.x;\n    layout->max_x = 0;\n    layout->header_height = 0;\n    layout->footer_height = 0;\n    nk_layout_reset_min_row_height(ctx);\n    layout->row.index = 0;\n    layout->row.columns = 0;\n    layout->row.ratio = 0;\n    layout->row.item_width = 0;\n    layout->row.tree_depth = 0;\n    layout->row.height = panel_padding.y;\n    layout->has_scrolling = nk_true;\n    if (!(win->flags & NK_WINDOW_NO_SCROLLBAR))\n        layout->bounds.w -= scrollbar_size.x;\n    if (!nk_panel_is_nonblock(panel_type)) {\n        layout->footer_height = 0;\n        if (!(win->flags & NK_WINDOW_NO_SCROLLBAR) || win->flags & NK_WINDOW_SCALABLE)\n            layout->footer_height = scrollbar_size.y;\n        layout->bounds.h -= layout->footer_height;\n    }\n\n    /* panel header */\n    if (nk_panel_has_header(win->flags, title))\n    {\n        struct nk_text text;\n        struct nk_rect header;\n        const struct nk_style_item *background = 0;\n\n        /* calculate header bounds */\n        header.x = win->bounds.x;\n        header.y = win->bounds.y;\n        header.w = win->bounds.w;\n        header.h = font->height + 2.0f * style->window.header.padding.y;\n        header.h += (2.0f * style->window.header.label_padding.y);\n\n        /* shrink panel by header */\n        layout->header_height = header.h;\n        layout->bounds.y += header.h;\n        layout->bounds.h -= header.h;\n        layout->at_y += header.h;\n\n        /* select correct header background and text color */\n        if (ctx->active == win) {\n            background = &style->window.header.active;\n            text.text = style->window.header.label_active;\n        } else if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) {\n            background = &style->window.header.hover;\n            text.text = style->window.header.label_hover;\n        } else {\n            background = &style->window.header.normal;\n            text.text = style->window.header.label_normal;\n        }\n\n        /* draw header background */\n        header.h += 1.0f;\n\n        switch(background->type) {\n            case NK_STYLE_ITEM_IMAGE:\n                text.background = nk_rgba(0,0,0,0);\n                nk_draw_image(&win->buffer, header, &background->data.image, nk_white);\n                break;\n            case NK_STYLE_ITEM_NINE_SLICE:\n                text.background = nk_rgba(0, 0, 0, 0);\n                nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_white);\n                break;\n            case NK_STYLE_ITEM_COLOR:\n                text.background = background->data.color;\n                nk_fill_rect(out, header, 0, background->data.color);\n                break;\n        }\n\n        /* window close button */\n        {struct nk_rect button;\n        button.y = header.y + style->window.header.padding.y;\n        button.h = header.h - 2 * style->window.header.padding.y;\n        button.w = button.h;\n        if (win->flags & NK_WINDOW_CLOSABLE) {\n            nk_flags ws = 0;\n            if (style->window.header.align == NK_HEADER_RIGHT) {\n                button.x = (header.w + header.x) - (button.w + style->window.header.padding.x);\n                header.w -= button.w + style->window.header.spacing.x + style->window.header.padding.x;\n            } else {\n                button.x = header.x + style->window.header.padding.x;\n                header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x;\n            }\n\n            if (nk_do_button_symbol(&ws, &win->buffer, button,\n                style->window.header.close_symbol, NK_BUTTON_DEFAULT,\n                &style->window.header.close_button, in, style->font) && !(win->flags & NK_WINDOW_ROM))\n            {\n                layout->flags |= NK_WINDOW_HIDDEN;\n                layout->flags &= (nk_flags)~NK_WINDOW_MINIMIZED;\n            }\n        }\n\n        /* window minimize button */\n        if (win->flags & NK_WINDOW_MINIMIZABLE) {\n            nk_flags ws = 0;\n            if (style->window.header.align == NK_HEADER_RIGHT) {\n                button.x = (header.w + header.x) - button.w;\n                if (!(win->flags & NK_WINDOW_CLOSABLE)) {\n                    button.x -= style->window.header.padding.x;\n                    header.w -= style->window.header.padding.x;\n                }\n                header.w -= button.w + style->window.header.spacing.x;\n            } else {\n                button.x = header.x;\n                header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x;\n            }\n            if (nk_do_button_symbol(&ws, &win->buffer, button, (layout->flags & NK_WINDOW_MINIMIZED)?\n                style->window.header.maximize_symbol: style->window.header.minimize_symbol,\n                NK_BUTTON_DEFAULT, &style->window.header.minimize_button, in, style->font) && !(win->flags & NK_WINDOW_ROM))\n                layout->flags = (layout->flags & NK_WINDOW_MINIMIZED) ?\n                    layout->flags & (nk_flags)~NK_WINDOW_MINIMIZED:\n                    layout->flags | NK_WINDOW_MINIMIZED;\n        }}\n\n        {/* window header title */\n        int text_len = nk_strlen(title);\n        struct nk_rect label = {0,0,0,0};\n        float t = font->width(font->userdata, font->height, title, text_len);\n        text.padding = nk_vec2(0,0);\n\n        label.x = header.x + style->window.header.padding.x;\n        label.x += style->window.header.label_padding.x;\n        label.y = header.y + style->window.header.label_padding.y;\n        label.h = font->height + 2 * style->window.header.label_padding.y;\n        label.w = t + 2 * style->window.header.spacing.x;\n        label.w = NK_CLAMP(0, label.w, header.x + header.w - label.x);\n        nk_widget_text(out, label, (const char*)title, text_len, &text, NK_TEXT_LEFT, font);}\n    }\n\n    /* draw window background */\n    if (!(layout->flags & NK_WINDOW_MINIMIZED) && !(layout->flags & NK_WINDOW_DYNAMIC)) {\n        struct nk_rect body;\n        body.x = win->bounds.x;\n        body.w = win->bounds.w;\n        body.y = (win->bounds.y + layout->header_height);\n        body.h = (win->bounds.h - layout->header_height);\n\n        switch(style->window.fixed_background.type) {\n            case NK_STYLE_ITEM_IMAGE:\n                nk_draw_image(out, body, &style->window.fixed_background.data.image, nk_white);\n                break;\n            case NK_STYLE_ITEM_NINE_SLICE:\n                nk_draw_nine_slice(out, body, &style->window.fixed_background.data.slice, nk_white);\n                break;\n            case NK_STYLE_ITEM_COLOR:\n                nk_fill_rect(out, body, style->window.rounding, style->window.fixed_background.data.color);\n                break;\n        }\n    }\n\n    /* set clipping rectangle */\n    {struct nk_rect clip;\n    layout->clip = layout->bounds;\n    nk_unify(&clip, &win->buffer.clip, layout->clip.x, layout->clip.y,\n        layout->clip.x + layout->clip.w, layout->clip.y + layout->clip.h);\n    nk_push_scissor(out, clip);\n    layout->clip = clip;}\n    return !(layout->flags & NK_WINDOW_HIDDEN) && !(layout->flags & NK_WINDOW_MINIMIZED);\n}\nNK_LIB void\nnk_panel_end(struct nk_context *ctx)\n{\n    struct nk_input *in;\n    struct nk_window *window;\n    struct nk_panel *layout;\n    const struct nk_style *style;\n    struct nk_command_buffer *out;\n\n    struct nk_vec2 scrollbar_size;\n    struct nk_vec2 panel_padding;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    window = ctx->current;\n    layout = window->layout;\n    style = &ctx->style;\n    out = &window->buffer;\n    in = (layout->flags & NK_WINDOW_ROM || layout->flags & NK_WINDOW_NO_INPUT) ? 0 :&ctx->input;\n    if (!nk_panel_is_sub(layout->type))\n        nk_push_scissor(out, nk_null_rect);\n\n    /* cache configuration data */\n    scrollbar_size = style->window.scrollbar_size;\n    panel_padding = nk_panel_get_padding(style, layout->type);\n\n    /* update the current cursor Y-position to point over the last added widget */\n    layout->at_y += layout->row.height;\n\n    /* dynamic panels */\n    if (layout->flags & NK_WINDOW_DYNAMIC && !(layout->flags & NK_WINDOW_MINIMIZED))\n    {\n        /* update panel height to fit dynamic growth */\n        struct nk_rect empty_space;\n        if (layout->at_y < (layout->bounds.y + layout->bounds.h))\n            layout->bounds.h = layout->at_y - layout->bounds.y;\n\n        /* fill top empty space */\n        empty_space.x = window->bounds.x;\n        empty_space.y = layout->bounds.y;\n        empty_space.h = panel_padding.y;\n        empty_space.w = window->bounds.w;\n        nk_fill_rect(out, empty_space, 0, style->window.background);\n\n        /* fill left empty space */\n        empty_space.x = window->bounds.x;\n        empty_space.y = layout->bounds.y;\n        empty_space.w = panel_padding.x + layout->border;\n        empty_space.h = layout->bounds.h;\n        nk_fill_rect(out, empty_space, 0, style->window.background);\n\n        /* fill right empty space */\n        empty_space.x = layout->bounds.x + layout->bounds.w;\n        empty_space.y = layout->bounds.y;\n        empty_space.w = panel_padding.x + layout->border;\n        empty_space.h = layout->bounds.h;\n        if (*layout->offset_y == 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR))\n            empty_space.w += scrollbar_size.x;\n        nk_fill_rect(out, empty_space, 0, style->window.background);\n\n        /* fill bottom empty space */\n        if (layout->footer_height > 0) {\n            empty_space.x = window->bounds.x;\n            empty_space.y = layout->bounds.y + layout->bounds.h;\n            empty_space.w = window->bounds.w;\n            empty_space.h = layout->footer_height;\n            nk_fill_rect(out, empty_space, 0, style->window.background);\n        }\n    }\n\n    /* scrollbars */\n    if (!(layout->flags & NK_WINDOW_NO_SCROLLBAR) &&\n        !(layout->flags & NK_WINDOW_MINIMIZED) &&\n        window->scrollbar_hiding_timer < NK_SCROLLBAR_HIDING_TIMEOUT)\n    {\n        struct nk_rect scroll;\n        int scroll_has_scrolling;\n        float scroll_target;\n        float scroll_offset;\n        float scroll_step;\n        float scroll_inc;\n\n        /* mouse wheel scrolling */\n        if (nk_panel_is_sub(layout->type))\n        {\n            /* sub-window mouse wheel scrolling */\n            struct nk_window *root_window = window;\n            struct nk_panel *root_panel = window->layout;\n            while (root_panel->parent)\n                root_panel = root_panel->parent;\n            while (root_window->parent)\n                root_window = root_window->parent;\n\n            /* only allow scrolling if parent window is active */\n            scroll_has_scrolling = nk_false;\n            if ((root_window == ctx->active) && layout->has_scrolling) {\n                /* and panel is being hovered and inside clip rect*/\n                if (nk_input_is_mouse_hovering_rect(in, layout->bounds) &&\n                    NK_INTERSECT(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->bounds.h,\n                        root_panel->clip.x, root_panel->clip.y, root_panel->clip.w, root_panel->clip.h))\n                {\n                    /* deactivate all parent scrolling */\n                    root_panel = window->layout;\n                    while (root_panel->parent) {\n                        root_panel->has_scrolling = nk_false;\n                        root_panel = root_panel->parent;\n                    }\n                    root_panel->has_scrolling = nk_false;\n                    scroll_has_scrolling = nk_true;\n                }\n            }\n        } else {\n            /* window mouse wheel scrolling */\n            scroll_has_scrolling = (window == ctx->active) && layout->has_scrolling;\n            if (in && (in->mouse.scroll_delta.y > 0 || in->mouse.scroll_delta.x > 0) && scroll_has_scrolling)\n                window->scrolled = nk_true;\n            else window->scrolled = nk_false;\n        }\n\n        {\n            /* vertical scrollbar */\n            nk_flags state = 0;\n            scroll.x = layout->bounds.x + layout->bounds.w + panel_padding.x;\n            scroll.y = layout->bounds.y;\n            scroll.w = scrollbar_size.x;\n            scroll.h = layout->bounds.h;\n\n            scroll_offset = (float)*layout->offset_y;\n            scroll_step = scroll.h * 0.10f;\n            scroll_inc = scroll.h * 0.01f;\n            scroll_target = (float)(int)(layout->at_y - scroll.y);\n            scroll_offset = nk_do_scrollbarv(&state, out, scroll, scroll_has_scrolling,\n                scroll_offset, scroll_target, scroll_step, scroll_inc,\n                &ctx->style.scrollv, in, style->font);\n            *layout->offset_y = (nk_uint)scroll_offset;\n            if (in && scroll_has_scrolling)\n                in->mouse.scroll_delta.y = 0;\n        }\n        {\n            /* horizontal scrollbar */\n            nk_flags state = 0;\n            scroll.x = layout->bounds.x;\n            scroll.y = layout->bounds.y + layout->bounds.h;\n            scroll.w = layout->bounds.w;\n            scroll.h = scrollbar_size.y;\n\n            scroll_offset = (float)*layout->offset_x;\n            scroll_target = (float)(int)(layout->max_x - scroll.x);\n            scroll_step = layout->max_x * 0.05f;\n            scroll_inc = layout->max_x * 0.005f;\n            scroll_offset = nk_do_scrollbarh(&state, out, scroll, scroll_has_scrolling,\n                scroll_offset, scroll_target, scroll_step, scroll_inc,\n                &ctx->style.scrollh, in, style->font);\n            *layout->offset_x = (nk_uint)scroll_offset;\n        }\n    }\n\n    /* hide scroll if no user input */\n    if (window->flags & NK_WINDOW_SCROLL_AUTO_HIDE) {\n        int has_input = nk_input_is_mouse_moved(&ctx->input) || ctx->input.mouse.scroll_delta.y != 0;\n        int is_window_hovered = nk_window_is_hovered(ctx);\n        int any_item_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);\n        if ((!has_input && is_window_hovered) || (!is_window_hovered && !any_item_active))\n            window->scrollbar_hiding_timer += ctx->delta_time_seconds;\n        else window->scrollbar_hiding_timer = 0;\n    } else window->scrollbar_hiding_timer = 0;\n\n    /* window border */\n    if (layout->flags & NK_WINDOW_BORDER)\n    {\n        struct nk_color border_color = nk_panel_get_border_color(style, layout->type);\n        const float padding_y = (layout->flags & NK_WINDOW_MINIMIZED)\n            ? (style->window.border + window->bounds.y + layout->header_height)\n            : ((layout->flags & NK_WINDOW_DYNAMIC)\n                ? (layout->bounds.y + layout->bounds.h + layout->footer_height)\n                : (window->bounds.y + window->bounds.h));\n        struct nk_rect b = window->bounds;\n        b.h = padding_y - window->bounds.y;\n        nk_stroke_rect(out, b, style->window.rounding, layout->border, border_color);\n    }\n\n    /* scaler */\n    if ((layout->flags & NK_WINDOW_SCALABLE) && in && !(layout->flags & NK_WINDOW_MINIMIZED))\n    {\n        /* calculate scaler bounds */\n        struct nk_rect scaler;\n        scaler.w = scrollbar_size.x;\n        scaler.h = scrollbar_size.y;\n        scaler.y = layout->bounds.y + layout->bounds.h;\n        if (layout->flags & NK_WINDOW_SCALE_LEFT)\n            scaler.x = layout->bounds.x - panel_padding.x * 0.5f;\n        else scaler.x = layout->bounds.x + layout->bounds.w + panel_padding.x;\n        if (layout->flags & NK_WINDOW_NO_SCROLLBAR)\n            scaler.x -= scaler.w;\n\n        /* draw scaler */\n        {const struct nk_style_item *item = &style->window.scaler;\n        if (item->type == NK_STYLE_ITEM_IMAGE)\n            nk_draw_image(out, scaler, &item->data.image, nk_white);\n        else {\n            if (layout->flags & NK_WINDOW_SCALE_LEFT) {\n                nk_fill_triangle(out, scaler.x, scaler.y, scaler.x,\n                    scaler.y + scaler.h, scaler.x + scaler.w,\n                    scaler.y + scaler.h, item->data.color);\n            } else {\n                nk_fill_triangle(out, scaler.x + scaler.w, scaler.y, scaler.x + scaler.w,\n                    scaler.y + scaler.h, scaler.x, scaler.y + scaler.h, item->data.color);\n            }\n        }}\n\n        /* do window scaling */\n        if (!(window->flags & NK_WINDOW_ROM)) {\n            struct nk_vec2 window_size = style->window.min_size;\n            int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;\n            int left_mouse_click_in_scaler = nk_input_has_mouse_click_down_in_rect(in,\n                    NK_BUTTON_LEFT, scaler, nk_true);\n\n            if (left_mouse_down && left_mouse_click_in_scaler) {\n                float delta_x = in->mouse.delta.x;\n                if (layout->flags & NK_WINDOW_SCALE_LEFT) {\n                    delta_x = -delta_x;\n                    window->bounds.x += in->mouse.delta.x;\n                }\n                /* dragging in x-direction  */\n                if (window->bounds.w + delta_x >= window_size.x) {\n                    if ((delta_x < 0) || (delta_x > 0 && in->mouse.pos.x >= scaler.x)) {\n                        window->bounds.w = window->bounds.w + delta_x;\n                        scaler.x += in->mouse.delta.x;\n                    }\n                }\n                /* dragging in y-direction (only possible if static window) */\n                if (!(layout->flags & NK_WINDOW_DYNAMIC)) {\n                    if (window_size.y < window->bounds.h + in->mouse.delta.y) {\n                        if ((in->mouse.delta.y < 0) || (in->mouse.delta.y > 0 && in->mouse.pos.y >= scaler.y)) {\n                            window->bounds.h = window->bounds.h + in->mouse.delta.y;\n                            scaler.y += in->mouse.delta.y;\n                        }\n                    }\n                }\n                ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT];\n                in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f;\n                in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f;\n            }\n        }\n    }\n    if (!nk_panel_is_sub(layout->type)) {\n        /* window is hidden so clear command buffer  */\n        if (layout->flags & NK_WINDOW_HIDDEN)\n            nk_command_buffer_reset(&window->buffer);\n        /* window is visible and not tab */\n        else nk_finish(ctx, window);\n    }\n\n    /* NK_WINDOW_REMOVE_ROM flag was set so remove NK_WINDOW_ROM */\n    if (layout->flags & NK_WINDOW_REMOVE_ROM) {\n        layout->flags &= ~(nk_flags)NK_WINDOW_ROM;\n        layout->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM;\n    }\n    window->flags = layout->flags;\n\n    /* property garbage collector */\n    if (window->property.active && window->property.old != window->property.seq &&\n        window->property.active == window->property.prev) {\n        nk_zero(&window->property, sizeof(window->property));\n    } else {\n        window->property.old = window->property.seq;\n        window->property.prev = window->property.active;\n        window->property.seq = 0;\n    }\n    /* edit garbage collector */\n    if (window->edit.active && window->edit.old != window->edit.seq &&\n       window->edit.active == window->edit.prev) {\n        nk_zero(&window->edit, sizeof(window->edit));\n    } else {\n        window->edit.old = window->edit.seq;\n        window->edit.prev = window->edit.active;\n        window->edit.seq = 0;\n    }\n    /* contextual garbage collector */\n    if (window->popup.active_con && window->popup.con_old != window->popup.con_count) {\n        window->popup.con_count = 0;\n        window->popup.con_old = 0;\n        window->popup.active_con = 0;\n    } else {\n        window->popup.con_old = window->popup.con_count;\n        window->popup.con_count = 0;\n    }\n    window->popup.combo_count = 0;\n    /* helper to make sure you have a 'nk_tree_push' for every 'nk_tree_pop' */\n    NK_ASSERT(!layout->row.tree_depth);\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                              WINDOW\n *\n * ===============================================================*/\nNK_LIB void*\nnk_create_window(struct nk_context *ctx)\n{\n    struct nk_page_element *elem;\n    elem = nk_create_page_element(ctx);\n    if (!elem) return 0;\n    elem->data.win.seq = ctx->seq;\n    return &elem->data.win;\n}\nNK_LIB void\nnk_free_window(struct nk_context *ctx, struct nk_window *win)\n{\n    /* unlink windows from list */\n    struct nk_table *it = win->tables;\n    if (win->popup.win) {\n        nk_free_window(ctx, win->popup.win);\n        win->popup.win = 0;\n    }\n    win->next = 0;\n    win->prev = 0;\n\n    while (it) {\n        /*free window state tables */\n        struct nk_table *n = it->next;\n        nk_remove_table(win, it);\n        nk_free_table(ctx, it);\n        if (it == win->tables)\n            win->tables = n;\n        it = n;\n    }\n\n    /* link windows into freelist */\n    {union nk_page_data *pd = NK_CONTAINER_OF(win, union nk_page_data, win);\n    struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);\n    nk_free_page_element(ctx, pe);}\n}\nNK_LIB struct nk_window*\nnk_find_window(const struct nk_context *ctx, nk_hash hash, const char *name)\n{\n    struct nk_window *iter;\n    iter = ctx->begin;\n    while (iter) {\n        NK_ASSERT(iter != iter->next);\n        if (iter->name == hash) {\n            int max_len = nk_strlen(iter->name_string);\n            if (!nk_stricmpn(iter->name_string, name, max_len))\n                return iter;\n        }\n        iter = iter->next;\n    }\n    return 0;\n}\nNK_LIB void\nnk_insert_window(struct nk_context *ctx, struct nk_window *win,\n    enum nk_window_insert_location loc)\n{\n    const struct nk_window *iter;\n    NK_ASSERT(ctx);\n    NK_ASSERT(win);\n    if (!win || !ctx) return;\n\n    iter = ctx->begin;\n    while (iter) {\n        NK_ASSERT(iter != iter->next);\n        NK_ASSERT(iter != win);\n        if (iter == win) return;\n        iter = iter->next;\n    }\n\n    if (!ctx->begin) {\n        win->next = 0;\n        win->prev = 0;\n        ctx->begin = win;\n        ctx->end = win;\n        ctx->count = 1;\n        return;\n    }\n    if (loc == NK_INSERT_BACK) {\n        struct nk_window *end;\n        end = ctx->end;\n        end->flags |= NK_WINDOW_ROM;\n        end->next = win;\n        win->prev = ctx->end;\n        win->next = 0;\n        ctx->end = win;\n        ctx->active = ctx->end;\n        ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM;\n    } else {\n        /*ctx->end->flags |= NK_WINDOW_ROM;*/\n        ctx->begin->prev = win;\n        win->next = ctx->begin;\n        win->prev = 0;\n        ctx->begin = win;\n        ctx->begin->flags &= ~(nk_flags)NK_WINDOW_ROM;\n    }\n    ctx->count++;\n}\nNK_LIB void\nnk_remove_window(struct nk_context *ctx, struct nk_window *win)\n{\n    if (win == ctx->begin || win == ctx->end) {\n        if (win == ctx->begin) {\n            ctx->begin = win->next;\n            if (win->next)\n                win->next->prev = 0;\n        }\n        if (win == ctx->end) {\n            ctx->end = win->prev;\n            if (win->prev)\n                win->prev->next = 0;\n        }\n    } else {\n        if (win->next)\n            win->next->prev = win->prev;\n        if (win->prev)\n            win->prev->next = win->next;\n    }\n    if (win == ctx->active || !ctx->active) {\n        ctx->active = ctx->end;\n        if (ctx->end)\n            ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM;\n    }\n    win->next = 0;\n    win->prev = 0;\n    ctx->count--;\n}\nNK_API nk_bool\nnk_begin(struct nk_context *ctx, const char *title,\n    struct nk_rect bounds, nk_flags flags)\n{\n    return nk_begin_titled(ctx, title, title, bounds, flags);\n}\nNK_API nk_bool\nnk_begin_titled(struct nk_context *ctx, const char *name, const char *title,\n    struct nk_rect bounds, nk_flags flags)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    nk_hash name_hash;\n    int name_len;\n    int ret = 0;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n    NK_ASSERT(title);\n    NK_ASSERT(ctx->style.font && ctx->style.font->width && \"if this triggers you forgot to add a font\");\n    NK_ASSERT(!ctx->current && \"if this triggers you missed a `nk_end` call\");\n    if (!ctx || ctx->current || !title || !name)\n        return 0;\n\n    /* find or create window */\n    style = &ctx->style;\n    name_len = (int)nk_strlen(name);\n    name_hash = nk_murmur_hash(name, (int)name_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, name_hash, name);\n    if (!win) {\n        /* create new window */\n        nk_size name_length = (nk_size)name_len;\n        win = (struct nk_window*)nk_create_window(ctx);\n        NK_ASSERT(win);\n        if (!win) return 0;\n\n        if (flags & NK_WINDOW_BACKGROUND)\n            nk_insert_window(ctx, win, NK_INSERT_FRONT);\n        else nk_insert_window(ctx, win, NK_INSERT_BACK);\n        nk_command_buffer_init(&win->buffer, &ctx->memory, NK_CLIPPING_ON);\n\n        win->flags = flags;\n        win->bounds = bounds;\n        win->name = name_hash;\n        name_length = NK_MIN(name_length, NK_WINDOW_MAX_NAME-1);\n        NK_MEMCPY(win->name_string, name, name_length);\n        win->name_string[name_length] = 0;\n        win->popup.win = 0;\n        win->widgets_disabled = nk_false;\n        if (!ctx->active)\n            ctx->active = win;\n    } else {\n        /* update window */\n        win->flags &= ~(nk_flags)(NK_WINDOW_PRIVATE-1);\n        win->flags |= flags;\n        if (!(win->flags & (NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE)))\n            win->bounds = bounds;\n        /* If this assert triggers you either:\n         *\n         * I.) Have more than one window with the same name or\n         * II.) You forgot to actually draw the window.\n         *      More specific you did not call `nk_clear` (nk_clear will be\n         *      automatically called for you if you are using one of the\n         *      provided demo backends). */\n        NK_ASSERT(win->seq != ctx->seq);\n        win->seq = ctx->seq;\n        if (!ctx->active && !(win->flags & NK_WINDOW_HIDDEN)) {\n            ctx->active = win;\n            ctx->end = win;\n        }\n    }\n    if (win->flags & NK_WINDOW_HIDDEN) {\n        ctx->current = win;\n        win->layout = 0;\n        return 0;\n    } else nk_start(ctx, win);\n\n    /* window overlapping */\n    if (!(win->flags & NK_WINDOW_HIDDEN) && !(win->flags & NK_WINDOW_NO_INPUT))\n    {\n        int inpanel, ishovered;\n        struct nk_window *iter = win;\n        float h = ctx->style.font->height + 2.0f * style->window.header.padding.y +\n            (2.0f * style->window.header.label_padding.y);\n        struct nk_rect win_bounds = (!(win->flags & NK_WINDOW_MINIMIZED))?\n            win->bounds: nk_rect(win->bounds.x, win->bounds.y, win->bounds.w, h);\n\n        /* activate window if hovered and no other window is overlapping this window */\n        inpanel = nk_input_has_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_LEFT, win_bounds, nk_true);\n        inpanel = inpanel && ctx->input.mouse.buttons[NK_BUTTON_LEFT].clicked;\n        ishovered = nk_input_is_mouse_hovering_rect(&ctx->input, win_bounds);\n        if ((win != ctx->active) && ishovered && !ctx->input.mouse.buttons[NK_BUTTON_LEFT].down) {\n            iter = win->next;\n            while (iter) {\n                struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))?\n                    iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h);\n                if (NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,\n                    iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) &&\n                    (!(iter->flags & NK_WINDOW_HIDDEN)))\n                    break;\n\n                if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) &&\n                    NK_INTERSECT(win->bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,\n                    iter->popup.win->bounds.x, iter->popup.win->bounds.y,\n                    iter->popup.win->bounds.w, iter->popup.win->bounds.h))\n                    break;\n                iter = iter->next;\n            }\n        }\n\n        /* activate window if clicked */\n        if (iter && inpanel && (win != ctx->end)) {\n            iter = win->next;\n            while (iter) {\n                /* try to find a panel with higher priority in the same position */\n                struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))?\n                iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h);\n                if (NK_INBOX(ctx->input.mouse.pos.x, ctx->input.mouse.pos.y,\n                    iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) &&\n                    !(iter->flags & NK_WINDOW_HIDDEN))\n                    break;\n                if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) &&\n                    NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,\n                    iter->popup.win->bounds.x, iter->popup.win->bounds.y,\n                    iter->popup.win->bounds.w, iter->popup.win->bounds.h))\n                    break;\n                iter = iter->next;\n            }\n        }\n        if (iter && !(win->flags & NK_WINDOW_ROM) && (win->flags & NK_WINDOW_BACKGROUND)) {\n            win->flags |= (nk_flags)NK_WINDOW_ROM;\n            iter->flags &= ~(nk_flags)NK_WINDOW_ROM;\n            ctx->active = iter;\n            if (!(iter->flags & NK_WINDOW_BACKGROUND)) {\n                /* current window is active in that position so transfer to top\n                 * at the highest priority in stack */\n                nk_remove_window(ctx, iter);\n                nk_insert_window(ctx, iter, NK_INSERT_BACK);\n            }\n        } else {\n            if (!iter && ctx->end != win) {\n                if (!(win->flags & NK_WINDOW_BACKGROUND)) {\n                    /* current window is active in that position so transfer to top\n                     * at the highest priority in stack */\n                    nk_remove_window(ctx, win);\n                    nk_insert_window(ctx, win, NK_INSERT_BACK);\n                }\n                win->flags &= ~(nk_flags)NK_WINDOW_ROM;\n                ctx->active = win;\n            }\n            if (ctx->end != win && !(win->flags & NK_WINDOW_BACKGROUND))\n                win->flags |= NK_WINDOW_ROM;\n        }\n    }\n    win->layout = (struct nk_panel*)nk_create_panel(ctx);\n    ctx->current = win;\n    ret = nk_panel_begin(ctx, title, NK_PANEL_WINDOW);\n    win->layout->offset_x = &win->scrollbar.x;\n    win->layout->offset_y = &win->scrollbar.y;\n    return ret;\n}\nNK_API void\nnk_end(struct nk_context *ctx)\n{\n    struct nk_panel *layout;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current && \"if this triggers you forgot to call `nk_begin`\");\n    if (!ctx || !ctx->current)\n        return;\n\n    layout = ctx->current->layout;\n    if (!layout || (layout->type == NK_PANEL_WINDOW && (ctx->current->flags & NK_WINDOW_HIDDEN))) {\n        ctx->current = 0;\n        return;\n    }\n    nk_panel_end(ctx);\n    nk_free_panel(ctx, ctx->current->layout);\n    ctx->current = 0;\n}\nNK_API struct nk_rect\nnk_window_get_bounds(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return nk_rect(0,0,0,0);\n    return ctx->current->bounds;\n}\nNK_API struct nk_vec2\nnk_window_get_position(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return nk_vec2(0,0);\n    return nk_vec2(ctx->current->bounds.x, ctx->current->bounds.y);\n}\nNK_API struct nk_vec2\nnk_window_get_size(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return nk_vec2(0,0);\n    return nk_vec2(ctx->current->bounds.w, ctx->current->bounds.h);\n}\nNK_API float\nnk_window_get_width(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return 0;\n    return ctx->current->bounds.w;\n}\nNK_API float\nnk_window_get_height(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return 0;\n    return ctx->current->bounds.h;\n}\nNK_API struct nk_rect\nnk_window_get_content_region(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return nk_rect(0,0,0,0);\n    return ctx->current->layout->clip;\n}\nNK_API struct nk_vec2\nnk_window_get_content_region_min(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current) return nk_vec2(0,0);\n    return nk_vec2(ctx->current->layout->clip.x, ctx->current->layout->clip.y);\n}\nNK_API struct nk_vec2\nnk_window_get_content_region_max(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current) return nk_vec2(0,0);\n    return nk_vec2(ctx->current->layout->clip.x + ctx->current->layout->clip.w,\n        ctx->current->layout->clip.y + ctx->current->layout->clip.h);\n}\nNK_API struct nk_vec2\nnk_window_get_content_region_size(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current) return nk_vec2(0,0);\n    return nk_vec2(ctx->current->layout->clip.w, ctx->current->layout->clip.h);\n}\nNK_API struct nk_command_buffer*\nnk_window_get_canvas(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current) return 0;\n    return &ctx->current->buffer;\n}\nNK_API struct nk_panel*\nnk_window_get_panel(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return 0;\n    return ctx->current->layout;\n}\nNK_API void\nnk_window_get_scroll(const struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)\n{\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return ;\n    win = ctx->current;\n    if (offset_x)\n      *offset_x = win->scrollbar.x;\n    if (offset_y)\n      *offset_y = win->scrollbar.y;\n}\nNK_API nk_bool\nnk_window_has_focus(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current) return 0;\n    return ctx->current == ctx->active;\n}\nNK_API nk_bool\nnk_window_is_hovered(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current || (ctx->current->flags & NK_WINDOW_HIDDEN))\n        return 0;\n    else {\n        struct nk_rect actual_bounds = ctx->current->bounds;\n        if (ctx->current->flags & NK_WINDOW_MINIMIZED) {\n            actual_bounds.h = ctx->current->layout->header_height;\n        }\n        return nk_input_is_mouse_hovering_rect(&ctx->input, actual_bounds);\n    }\n}\nNK_API nk_bool\nnk_window_is_any_hovered(const struct nk_context *ctx)\n{\n    struct nk_window *iter;\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    iter = ctx->begin;\n    while (iter) {\n        /* check if window is being hovered */\n        if(!(iter->flags & NK_WINDOW_HIDDEN)) {\n            /* check if window popup is being hovered */\n            if (iter->popup.active && iter->popup.win && nk_input_is_mouse_hovering_rect(&ctx->input, iter->popup.win->bounds))\n                return 1;\n\n            if (iter->flags & NK_WINDOW_MINIMIZED) {\n                struct nk_rect header = iter->bounds;\n                header.h = ctx->style.font->height + 2 * ctx->style.window.header.padding.y;\n                if (nk_input_is_mouse_hovering_rect(&ctx->input, header))\n                    return 1;\n            } else if (nk_input_is_mouse_hovering_rect(&ctx->input, iter->bounds)) {\n                return 1;\n            }\n        }\n        iter = iter->next;\n    }\n    return 0;\n}\nNK_API nk_bool\nnk_item_is_any_active(const struct nk_context *ctx)\n{\n    int any_hovered = nk_window_is_any_hovered(ctx);\n    int any_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);\n    return any_hovered || any_active;\n}\nNK_API nk_bool\nnk_window_is_collapsed(const struct nk_context *ctx, const char *name)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (!win) return 0;\n    return win->flags & NK_WINDOW_MINIMIZED;\n}\nNK_API nk_bool\nnk_window_is_closed(const struct nk_context *ctx, const char *name)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return 1;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (!win) return 1;\n    return (win->flags & NK_WINDOW_CLOSED);\n}\nNK_API nk_bool\nnk_window_is_hidden(const struct nk_context *ctx, const char *name)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return 1;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (!win) return 1;\n    return (win->flags & NK_WINDOW_HIDDEN);\n}\nNK_API nk_bool\nnk_window_is_active(const struct nk_context *ctx, const char *name)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (!win) return 0;\n    return win == ctx->active;\n}\nNK_API struct nk_window*\nnk_window_find(const struct nk_context *ctx, const char *name)\n{\n    int title_len;\n    nk_hash title_hash;\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    return nk_find_window(ctx, title_hash, name);\n}\nNK_API void\nnk_window_close(struct nk_context *ctx, const char *name)\n{\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    win = nk_window_find(ctx, name);\n    if (!win) return;\n    NK_ASSERT(ctx->current != win && \"You cannot close a currently active window\");\n    if (ctx->current == win) return;\n    win->flags |= NK_WINDOW_HIDDEN;\n    win->flags |= NK_WINDOW_CLOSED;\n}\nNK_API void\nnk_window_set_bounds(struct nk_context *ctx,\n    const char *name, struct nk_rect bounds)\n{\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    win = nk_window_find(ctx, name);\n    if (!win) return;\n    win->bounds = bounds;\n}\nNK_API void\nnk_window_set_position(struct nk_context *ctx,\n    const char *name, struct nk_vec2 pos)\n{\n    struct nk_window *win = nk_window_find(ctx, name);\n    if (!win) return;\n    win->bounds.x = pos.x;\n    win->bounds.y = pos.y;\n}\nNK_API void\nnk_window_set_size(struct nk_context *ctx,\n    const char *name, struct nk_vec2 size)\n{\n    struct nk_window *win = nk_window_find(ctx, name);\n    if (!win) return;\n    win->bounds.w = size.x;\n    win->bounds.h = size.y;\n}\nNK_API void\nnk_window_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y)\n{\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return;\n    win = ctx->current;\n    win->scrollbar.x = offset_x;\n    win->scrollbar.y = offset_y;\n}\nNK_API void\nnk_window_collapse(struct nk_context *ctx, const char *name,\n                    enum nk_collapse_states c)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (!win) return;\n    if (c == NK_MINIMIZED)\n        win->flags |= NK_WINDOW_MINIMIZED;\n    else win->flags &= ~(nk_flags)NK_WINDOW_MINIMIZED;\n}\nNK_API void\nnk_window_collapse_if(struct nk_context *ctx, const char *name,\n    enum nk_collapse_states c, int cond)\n{\n    NK_ASSERT(ctx);\n    if (!ctx || !cond) return;\n    nk_window_collapse(ctx, name, c);\n}\nNK_API void\nnk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states s)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (!win) return;\n    if (s == NK_HIDDEN) {\n        win->flags |= NK_WINDOW_HIDDEN;\n    } else win->flags &= ~(nk_flags)NK_WINDOW_HIDDEN;\n}\nNK_API void\nnk_window_show_if(struct nk_context *ctx, const char *name,\n    enum nk_show_states s, int cond)\n{\n    NK_ASSERT(ctx);\n    if (!ctx || !cond) return;\n    nk_window_show(ctx, name, s);\n}\n\nNK_API void\nnk_window_set_focus(struct nk_context *ctx, const char *name)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (win && ctx->end != win) {\n        nk_remove_window(ctx, win);\n        nk_insert_window(ctx, win, NK_INSERT_BACK);\n    }\n    ctx->active = win;\n}\nNK_API void\nnk_rule_horizontal(struct nk_context *ctx, struct nk_color color, nk_bool rounding)\n{\n    struct nk_rect space;\n    enum nk_widget_layout_states state = nk_widget(&space, ctx);\n    struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);\n    if (!state) return;\n    nk_fill_rect(canvas, space, rounding && space.h > 1.5f ? space.h / 2.0f : 0, color);\n}\n\n\n\n\n/* ===============================================================\n *\n *                              POPUP\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_popup_begin(struct nk_context *ctx, enum nk_popup_type type,\n    const char *title, nk_flags flags, struct nk_rect rect)\n{\n    struct nk_window *popup;\n    struct nk_window *win;\n    struct nk_panel *panel;\n\n    int title_len;\n    nk_hash title_hash;\n    nk_size allocated;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(title);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    panel = win->layout;\n    NK_ASSERT(!((int)panel->type & (int)NK_PANEL_SET_POPUP) && \"popups are not allowed to have popups\");\n    (void)panel;\n    title_len = (int)nk_strlen(title);\n    title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_POPUP);\n\n    popup = win->popup.win;\n    if (!popup) {\n        popup = (struct nk_window*)nk_create_window(ctx);\n        popup->parent = win;\n        win->popup.win = popup;\n        win->popup.active = 0;\n        win->popup.type = NK_PANEL_POPUP;\n    }\n\n    /* make sure we have correct popup */\n    if (win->popup.name != title_hash) {\n        if (!win->popup.active) {\n            nk_zero(popup, sizeof(*popup));\n            win->popup.name = title_hash;\n            win->popup.active = 1;\n            win->popup.type = NK_PANEL_POPUP;\n        } else return 0;\n    }\n\n    /* popup position is local to window */\n    ctx->current = popup;\n    rect.x += win->layout->clip.x;\n    rect.y += win->layout->clip.y;\n\n    /* setup popup data */\n    popup->parent = win;\n    popup->bounds = rect;\n    popup->seq = ctx->seq;\n    popup->layout = (struct nk_panel*)nk_create_panel(ctx);\n    popup->flags = flags;\n    popup->flags |= NK_WINDOW_BORDER;\n    if (type == NK_POPUP_DYNAMIC)\n        popup->flags |= NK_WINDOW_DYNAMIC;\n\n    popup->buffer = win->buffer;\n    nk_start_popup(ctx, win);\n    allocated = ctx->memory.allocated;\n    nk_push_scissor(&popup->buffer, nk_null_rect);\n\n    if (nk_panel_begin(ctx, title, NK_PANEL_POPUP)) {\n        /* popup is running therefore invalidate parent panels */\n        struct nk_panel *root;\n        root = win->layout;\n        while (root) {\n            root->flags |= NK_WINDOW_ROM;\n            root->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM;\n            root = root->parent;\n        }\n        win->popup.active = 1;\n        popup->layout->offset_x = &popup->scrollbar.x;\n        popup->layout->offset_y = &popup->scrollbar.y;\n        popup->layout->parent = win->layout;\n        return 1;\n    } else {\n        /* popup was closed/is invalid so cleanup */\n        struct nk_panel *root;\n        root = win->layout;\n        while (root) {\n            root->flags |= NK_WINDOW_REMOVE_ROM;\n            root = root->parent;\n        }\n        win->popup.buf.active = 0;\n        win->popup.active = 0;\n        ctx->memory.allocated = allocated;\n        ctx->current = win;\n        nk_free_panel(ctx, popup->layout);\n        popup->layout = 0;\n        return 0;\n    }\n}\nNK_LIB nk_bool\nnk_nonblock_begin(struct nk_context *ctx,\n    nk_flags flags, struct nk_rect body, struct nk_rect header,\n    enum nk_panel_type panel_type)\n{\n    struct nk_window *popup;\n    struct nk_window *win;\n    struct nk_panel *panel;\n    int is_active = nk_true;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    /* popups cannot have popups */\n    win = ctx->current;\n    panel = win->layout;\n    NK_ASSERT(!((int)panel->type & (int)NK_PANEL_SET_POPUP));\n    (void)panel;\n    popup = win->popup.win;\n    if (!popup) {\n        /* create window for nonblocking popup */\n        popup = (struct nk_window*)nk_create_window(ctx);\n        popup->parent = win;\n        win->popup.win = popup;\n        win->popup.type = panel_type;\n        nk_command_buffer_init(&popup->buffer, &ctx->memory, NK_CLIPPING_ON);\n    } else {\n        /* close the popup if user pressed outside or in the header */\n        int pressed, in_body, in_header;\n#ifdef NK_BUTTON_TRIGGER_ON_RELEASE\n        pressed = nk_input_is_mouse_released(&ctx->input, NK_BUTTON_LEFT);\n#else\n        pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);\n#endif\n        in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);\n        in_header = nk_input_is_mouse_hovering_rect(&ctx->input, header);\n        if (pressed && (!in_body || in_header))\n            is_active = nk_false;\n    }\n    win->popup.header = header;\n\n    if (!is_active) {\n        /* remove read only mode from all parent panels */\n        struct nk_panel *root = win->layout;\n        while (root) {\n            root->flags |= NK_WINDOW_REMOVE_ROM;\n            root = root->parent;\n        }\n        return is_active;\n    }\n    popup->bounds = body;\n    popup->parent = win;\n    popup->layout = (struct nk_panel*)nk_create_panel(ctx);\n    popup->flags = flags;\n    popup->flags |= NK_WINDOW_BORDER;\n    popup->flags |= NK_WINDOW_DYNAMIC;\n    popup->seq = ctx->seq;\n    win->popup.active = 1;\n    NK_ASSERT(popup->layout);\n\n    nk_start_popup(ctx, win);\n    popup->buffer = win->buffer;\n    nk_push_scissor(&popup->buffer, nk_null_rect);\n    ctx->current = popup;\n\n    nk_panel_begin(ctx, 0, panel_type);\n    win->buffer = popup->buffer;\n    popup->layout->parent = win->layout;\n    popup->layout->offset_x = &popup->scrollbar.x;\n    popup->layout->offset_y = &popup->scrollbar.y;\n\n    /* set read only mode to all parent panels */\n    {struct nk_panel *root;\n    root = win->layout;\n    while (root) {\n        root->flags |= NK_WINDOW_ROM;\n        root = root->parent;\n    }}\n    return is_active;\n}\nNK_API void\nnk_popup_close(struct nk_context *ctx)\n{\n    struct nk_window *popup;\n    NK_ASSERT(ctx);\n    if (!ctx || !ctx->current) return;\n\n    popup = ctx->current;\n    NK_ASSERT(popup->parent);\n    NK_ASSERT((int)popup->layout->type & (int)NK_PANEL_SET_POPUP);\n    popup->flags |= NK_WINDOW_HIDDEN;\n}\nNK_API void\nnk_popup_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_window *popup;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    popup = ctx->current;\n    if (!popup->parent) return;\n    win = popup->parent;\n    if (popup->flags & NK_WINDOW_HIDDEN) {\n        struct nk_panel *root;\n        root = win->layout;\n        while (root) {\n            root->flags |= NK_WINDOW_REMOVE_ROM;\n            root = root->parent;\n        }\n        win->popup.active = 0;\n    }\n    nk_push_scissor(&popup->buffer, nk_null_rect);\n    nk_end(ctx);\n\n    win->buffer = popup->buffer;\n    nk_finish_popup(ctx, win);\n    ctx->current = win;\n    nk_push_scissor(&win->buffer, win->layout->clip);\n}\nNK_API void\nnk_popup_get_scroll(const struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)\n{\n    struct nk_window *popup;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    popup = ctx->current;\n    if (offset_x)\n      *offset_x = popup->scrollbar.x;\n    if (offset_y)\n      *offset_y = popup->scrollbar.y;\n}\nNK_API void\nnk_popup_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y)\n{\n    struct nk_window *popup;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    popup = ctx->current;\n    popup->scrollbar.x = offset_x;\n    popup->scrollbar.y = offset_y;\n}\n\n\n\n\n/* ==============================================================\n *\n *                          CONTEXTUAL\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_contextual_begin(struct nk_context *ctx, nk_flags flags, struct nk_vec2 size,\n    struct nk_rect trigger_bounds)\n{\n    struct nk_window *win;\n    struct nk_window *popup;\n    struct nk_rect body;\n    struct nk_input* in;\n\n    NK_STORAGE const struct nk_rect null_rect = {-1,-1,0,0};\n    int is_clicked = 0;\n    int is_open = 0;\n    int ret = 0;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    ++win->popup.con_count;\n    if (ctx->current != ctx->active)\n        return 0;\n\n    /* check if currently active contextual is active */\n    popup = win->popup.win;\n    is_open = (popup && win->popup.type == NK_PANEL_CONTEXTUAL);\n    in = win->widgets_disabled ? 0 : &ctx->input;\n    if (in) {\n        is_clicked = nk_input_mouse_clicked(in, NK_BUTTON_RIGHT, trigger_bounds);\n        if (win->popup.active_con && win->popup.con_count != win->popup.active_con)\n            return 0;\n        if (!is_open && win->popup.active_con)\n            win->popup.active_con = 0;\n        if ((!is_open && !is_clicked))\n            return 0;\n\n        /* calculate contextual position on click */\n        win->popup.active_con = win->popup.con_count;\n        if (is_clicked) {\n            body.x = in->mouse.pos.x;\n            body.y = in->mouse.pos.y;\n        } else {\n            body.x = popup->bounds.x;\n            body.y = popup->bounds.y;\n        }\n\n        body.w = size.x;\n        body.h = size.y;\n\n        /* start nonblocking contextual popup */\n        ret = nk_nonblock_begin(ctx, flags | NK_WINDOW_NO_SCROLLBAR, body,\n            null_rect, NK_PANEL_CONTEXTUAL);\n        if (ret) win->popup.type = NK_PANEL_CONTEXTUAL;\n        else {\n            win->popup.active_con = 0;\n            win->popup.type = NK_PANEL_NONE;\n            if (win->popup.win)\n                win->popup.win->flags = 0;\n        }\n    }\n    return ret;\n}\nNK_API nk_bool\nnk_contextual_item_text(struct nk_context *ctx, const char *text, int len,\n    nk_flags alignment)\n{\n    struct nk_window *win;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);\n    if (!state) return nk_false;\n\n    in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,\n        text, len, alignment, NK_BUTTON_DEFAULT, &style->contextual_button, in, style->font)) {\n        nk_contextual_close(ctx);\n        return nk_true;\n    }\n    return nk_false;\n}\nNK_API nk_bool\nnk_contextual_item_label(struct nk_context *ctx, const char *label, nk_flags align)\n{\n    return nk_contextual_item_text(ctx, label, nk_strlen(label), align);\n}\nNK_API nk_bool\nnk_contextual_item_image_text(struct nk_context *ctx, struct nk_image img,\n    const char *text, int len, nk_flags align)\n{\n    struct nk_window *win;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);\n    if (!state) return nk_false;\n\n    in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, bounds,\n        img, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)){\n        nk_contextual_close(ctx);\n        return nk_true;\n    }\n    return nk_false;\n}\nNK_API nk_bool\nnk_contextual_item_image_label(struct nk_context *ctx, struct nk_image img,\n    const char *label, nk_flags align)\n{\n    return nk_contextual_item_image_text(ctx, img, label, nk_strlen(label), align);\n}\nNK_API nk_bool\nnk_contextual_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,\n    const char *text, int len, nk_flags align)\n{\n    struct nk_window *win;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);\n    if (!state) return nk_false;\n\n    in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,\n        symbol, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)) {\n        nk_contextual_close(ctx);\n        return nk_true;\n    }\n    return nk_false;\n}\nNK_API nk_bool\nnk_contextual_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,\n    const char *text, nk_flags align)\n{\n    return nk_contextual_item_symbol_text(ctx, symbol, text, nk_strlen(text), align);\n}\nNK_API void\nnk_contextual_close(struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) return;\n    nk_popup_close(ctx);\n}\nNK_API void\nnk_contextual_end(struct nk_context *ctx)\n{\n    struct nk_window *popup;\n    struct nk_panel *panel;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return;\n\n    popup = ctx->current;\n    panel = popup->layout;\n    NK_ASSERT(popup->parent);\n    NK_ASSERT((int)panel->type & (int)NK_PANEL_SET_POPUP);\n    if (panel->flags & NK_WINDOW_DYNAMIC) {\n        /* Close behavior\n        This is a bit of a hack solution since we do not know before we end our popup\n        how big it will be. We therefore do not directly know when a\n        click outside the non-blocking popup must close it at that direct frame.\n        Instead it will be closed in the next frame.*/\n        struct nk_rect body = {0,0,0,0};\n        if (panel->at_y < (panel->bounds.y + panel->bounds.h)) {\n            struct nk_vec2 padding = nk_panel_get_padding(&ctx->style, panel->type);\n            body = panel->bounds;\n            body.y = (panel->at_y + panel->footer_height + panel->border + padding.y + panel->row.height);\n            body.h = (panel->bounds.y + panel->bounds.h) - body.y;\n        }\n        {int pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);\n        int in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);\n        if (pressed && in_body)\n            popup->flags |= NK_WINDOW_HIDDEN;\n        }\n    }\n    if (popup->flags & NK_WINDOW_HIDDEN)\n        popup->seq = 0;\n    nk_popup_end(ctx);\n    return;\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                              MENU\n *\n * ===============================================================*/\nNK_API void\nnk_menubar_begin(struct nk_context *ctx)\n{\n    struct nk_panel *layout;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    layout = ctx->current->layout;\n    NK_ASSERT(layout->at_y == layout->bounds.y);\n    /* if this assert triggers you allocated space between nk_begin and nk_menubar_begin.\n    If you want a menubar the first nuklear function after `nk_begin` has to be a\n    `nk_menubar_begin` call. Inside the menubar you then have to allocate space for\n    widgets (also supports multiple rows).\n    Example:\n        if (nk_begin(...)) {\n            nk_menubar_begin(...);\n                nk_layout_xxxx(...);\n                nk_button(...);\n                nk_layout_xxxx(...);\n                nk_button(...);\n            nk_menubar_end(...);\n        }\n        nk_end(...);\n    */\n    if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED)\n        return;\n\n    layout->menu.x = layout->at_x;\n    layout->menu.y = layout->at_y + layout->row.height;\n    layout->menu.w = layout->bounds.w;\n    layout->menu.offset.x = *layout->offset_x;\n    layout->menu.offset.y = *layout->offset_y;\n    *layout->offset_y = 0;\n}\nNK_API void\nnk_menubar_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    struct nk_command_buffer *out;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    out = &win->buffer;\n    layout = win->layout;\n    if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED)\n        return;\n\n    layout->menu.h  = layout->at_y - layout->menu.y;\n    layout->menu.h += layout->row.height + ctx->style.window.spacing.y;\n\n    layout->bounds.y += layout->menu.h;\n    layout->bounds.h -= layout->menu.h;\n\n    *layout->offset_x = layout->menu.offset.x;\n    *layout->offset_y = layout->menu.offset.y;\n    layout->at_y      = layout->bounds.y - layout->row.height;\n\n    layout->clip.y = layout->bounds.y;\n    layout->clip.h = layout->bounds.h;\n    nk_push_scissor(out, layout->clip);\n}\nNK_INTERN int\nnk_menu_begin(struct nk_context *ctx, struct nk_window *win,\n    const char *id, int is_clicked, struct nk_rect header, struct nk_vec2 size)\n{\n    int is_open = 0;\n    int is_active = 0;\n    struct nk_rect body;\n    struct nk_window *popup;\n    nk_hash hash = nk_murmur_hash(id, (int)nk_strlen(id), NK_PANEL_MENU);\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    body.x = header.x;\n    body.w = size.x;\n    body.y = header.y + header.h;\n    body.h = size.y;\n\n    popup = win->popup.win;\n    is_open = popup ? nk_true : nk_false;\n    is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU);\n    if ((is_clicked && is_open && !is_active) || (is_open && !is_active) ||\n        (!is_open && !is_active && !is_clicked)) return 0;\n    if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU))\n        return 0;\n\n    win->popup.type = NK_PANEL_MENU;\n    win->popup.name = hash;\n    return 1;\n}\nNK_API nk_bool\nnk_menu_begin_text(struct nk_context *ctx, const char *title, int len,\n    nk_flags align, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    const struct nk_input *in;\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    nk_flags state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    state = nk_widget(&header, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, header,\n        title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font))\n        is_clicked = nk_true;\n    return nk_menu_begin(ctx, win, title, is_clicked, header, size);\n}\nNK_API nk_bool nk_menu_begin_label(struct nk_context *ctx,\n    const char *text, nk_flags align, struct nk_vec2 size)\n{\n    return nk_menu_begin_text(ctx, text, nk_strlen(text), align, size);\n}\nNK_API nk_bool\nnk_menu_begin_image(struct nk_context *ctx, const char *id, struct nk_image img,\n    struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_rect header;\n    const struct nk_input *in;\n    int is_clicked = nk_false;\n    nk_flags state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    state = nk_widget(&header, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_image(&ctx->last_widget_state, &win->buffer, header,\n        img, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in))\n        is_clicked = nk_true;\n    return nk_menu_begin(ctx, win, id, is_clicked, header, size);\n}\nNK_API nk_bool\nnk_menu_begin_symbol(struct nk_context *ctx, const char *id,\n    enum nk_symbol_type sym, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    const struct nk_input *in;\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    nk_flags state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    state = nk_widget(&header, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_symbol(&ctx->last_widget_state,  &win->buffer, header,\n        sym, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font))\n        is_clicked = nk_true;\n    return nk_menu_begin(ctx, win, id, is_clicked, header, size);\n}\nNK_API nk_bool\nnk_menu_begin_image_text(struct nk_context *ctx, const char *title, int len,\n    nk_flags align, struct nk_image img, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_rect header;\n    const struct nk_input *in;\n    int is_clicked = nk_false;\n    nk_flags state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    state = nk_widget(&header, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer,\n        header, img, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button,\n        ctx->style.font, in))\n        is_clicked = nk_true;\n    return nk_menu_begin(ctx, win, title, is_clicked, header, size);\n}\nNK_API nk_bool\nnk_menu_begin_image_label(struct nk_context *ctx,\n    const char *title, nk_flags align, struct nk_image img, struct nk_vec2 size)\n{\n    return nk_menu_begin_image_text(ctx, title, nk_strlen(title), align, img, size);\n}\nNK_API nk_bool\nnk_menu_begin_symbol_text(struct nk_context *ctx, const char *title, int len,\n    nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_rect header;\n    const struct nk_input *in;\n    int is_clicked = nk_false;\n    nk_flags state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    state = nk_widget(&header, ctx);\n    if (!state) return 0;\n\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer,\n        header, sym, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button,\n        ctx->style.font, in)) is_clicked = nk_true;\n    return nk_menu_begin(ctx, win, title, is_clicked, header, size);\n}\nNK_API nk_bool\nnk_menu_begin_symbol_label(struct nk_context *ctx,\n    const char *title, nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size )\n{\n    return nk_menu_begin_symbol_text(ctx, title, nk_strlen(title), align,sym,size);\n}\nNK_API nk_bool\nnk_menu_item_text(struct nk_context *ctx, const char *title, int len, nk_flags align)\n{\n    return nk_contextual_item_text(ctx, title, len, align);\n}\nNK_API nk_bool\nnk_menu_item_label(struct nk_context *ctx, const char *label, nk_flags align)\n{\n    return nk_contextual_item_label(ctx, label, align);\n}\nNK_API nk_bool\nnk_menu_item_image_label(struct nk_context *ctx, struct nk_image img,\n    const char *label, nk_flags align)\n{\n    return nk_contextual_item_image_label(ctx, img, label, align);\n}\nNK_API nk_bool\nnk_menu_item_image_text(struct nk_context *ctx, struct nk_image img,\n    const char *text, int len, nk_flags align)\n{\n    return nk_contextual_item_image_text(ctx, img, text, len, align);\n}\nNK_API nk_bool nk_menu_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *text, int len, nk_flags align)\n{\n    return nk_contextual_item_symbol_text(ctx, sym, text, len, align);\n}\nNK_API nk_bool nk_menu_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *label, nk_flags align)\n{\n    return nk_contextual_item_symbol_label(ctx, sym, label, align);\n}\nNK_API void nk_menu_close(struct nk_context *ctx)\n{\n    nk_contextual_close(ctx);\n}\nNK_API void\nnk_menu_end(struct nk_context *ctx)\n{\n    nk_contextual_end(ctx);\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                          LAYOUT\n *\n * ===============================================================*/\nNK_API void\nnk_layout_set_min_row_height(struct nk_context *ctx, float height)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    layout->row.min_height = height;\n}\nNK_API void\nnk_layout_reset_min_row_height(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    layout->row.min_height = ctx->style.font->height;\n    layout->row.min_height += ctx->style.text.padding.y*2;\n    layout->row.min_height += ctx->style.window.min_row_height_padding*2;\n}\nNK_LIB float\nnk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type,\n    float total_space, int columns)\n{\n    float panel_spacing;\n    float panel_space;\n\n    struct nk_vec2 spacing;\n\n    NK_UNUSED(type);\n\n    spacing = style->window.spacing;\n\n    /* calculate the usable panel space */\n    panel_spacing = (float)NK_MAX(columns - 1, 0) * spacing.x;\n    panel_space  = total_space - panel_spacing;\n    return panel_space;\n}\nNK_LIB void\nnk_panel_layout(const struct nk_context *ctx, struct nk_window *win,\n    float height, int cols)\n{\n    struct nk_panel *layout;\n    const struct nk_style *style;\n    struct nk_command_buffer *out;\n\n    struct nk_vec2 item_spacing;\n    struct nk_color color;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    /* prefetch some configuration data */\n    layout = win->layout;\n    style = &ctx->style;\n    out = &win->buffer;\n    color = style->window.background;\n    item_spacing = style->window.spacing;\n\n    /*  if one of these triggers you forgot to add an `if` condition around either\n        a window, group, popup, combobox or contextual menu `begin` and `end` block.\n        Example:\n            if (nk_begin(...) {...} nk_end(...); or\n            if (nk_group_begin(...) { nk_group_end(...);} */\n    NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));\n    NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));\n    NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));\n\n    /* update the current row and set the current row layout */\n    layout->row.index = 0;\n    layout->at_y += layout->row.height;\n    layout->row.columns = cols;\n    if (height == 0.0f)\n        layout->row.height = NK_MAX(height, layout->row.min_height) + item_spacing.y;\n    else layout->row.height = height + item_spacing.y;\n\n    layout->row.item_offset = 0;\n    if (layout->flags & NK_WINDOW_DYNAMIC) {\n        /* draw background for dynamic panels */\n        struct nk_rect background;\n        background.x = win->bounds.x;\n        background.w = win->bounds.w;\n        background.y = layout->at_y - 1.0f;\n        background.h = layout->row.height + 1.0f;\n        nk_fill_rect(out, background, 0, color);\n    }\n}\nNK_LIB void\nnk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt,\n    float height, int cols, int width)\n{\n    /* update the current row and set the current row layout */\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    nk_panel_layout(ctx, win, height, cols);\n    if (fmt == NK_DYNAMIC)\n        win->layout->row.type = NK_LAYOUT_DYNAMIC_FIXED;\n    else win->layout->row.type = NK_LAYOUT_STATIC_FIXED;\n\n    win->layout->row.ratio = 0;\n    win->layout->row.filled = 0;\n    win->layout->row.item_offset = 0;\n    win->layout->row.item_width = (float)width;\n}\nNK_API float\nnk_layout_ratio_from_pixel(const struct nk_context *ctx, float pixel_width)\n{\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    NK_ASSERT(pixel_width);\n    if (!ctx || !ctx->current || !ctx->current->layout) return 0;\n    win = ctx->current;\n    return NK_CLAMP(0.0f, pixel_width/win->bounds.x, 1.0f);\n}\nNK_API void\nnk_layout_row_dynamic(struct nk_context *ctx, float height, int cols)\n{\n    nk_row_layout(ctx, NK_DYNAMIC, height, cols, 0);\n}\nNK_API void\nnk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols)\n{\n    nk_row_layout(ctx, NK_STATIC, height, cols, item_width);\n}\nNK_API void\nnk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt,\n    float row_height, int cols)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    nk_panel_layout(ctx, win, row_height, cols);\n    if (fmt == NK_DYNAMIC)\n        layout->row.type = NK_LAYOUT_DYNAMIC_ROW;\n    else layout->row.type = NK_LAYOUT_STATIC_ROW;\n\n    layout->row.ratio = 0;\n    layout->row.filled = 0;\n    layout->row.item_width = 0;\n    layout->row.item_offset = 0;\n    layout->row.columns = cols;\n}\nNK_API void\nnk_layout_row_push(struct nk_context *ctx, float ratio_or_width)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);\n    if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)\n        return;\n\n    if (layout->row.type == NK_LAYOUT_DYNAMIC_ROW) {\n        float ratio = ratio_or_width;\n        if ((ratio + layout->row.filled) > 1.0f) return;\n        if (ratio > 0.0f)\n            layout->row.item_width = NK_SATURATE(ratio);\n        else layout->row.item_width = 1.0f - layout->row.filled;\n    } else layout->row.item_width = ratio_or_width;\n}\nNK_API void\nnk_layout_row_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);\n    if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)\n        return;\n    layout->row.item_width = 0;\n    layout->row.item_offset = 0;\n}\nNK_API void\nnk_layout_row(struct nk_context *ctx, enum nk_layout_format fmt,\n    float height, int cols, const float *ratio)\n{\n    int i;\n    int n_undef = 0;\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    nk_panel_layout(ctx, win, height, cols);\n    if (fmt == NK_DYNAMIC) {\n        /* calculate width of undefined widget ratios */\n        float r = 0;\n        layout->row.ratio = ratio;\n        for (i = 0; i < cols; ++i) {\n            if (ratio[i] < 0.0f)\n                n_undef++;\n            else r += ratio[i];\n        }\n        r = NK_SATURATE(1.0f - r);\n        layout->row.type = NK_LAYOUT_DYNAMIC;\n        layout->row.item_width = (r > 0 && n_undef > 0) ? (r / (float)n_undef):0;\n    } else {\n        layout->row.ratio = ratio;\n        layout->row.type = NK_LAYOUT_STATIC;\n        layout->row.item_width = 0;\n        layout->row.item_offset = 0;\n    }\n    layout->row.item_offset = 0;\n    layout->row.filled = 0;\n}\nNK_API void\nnk_layout_row_template_begin(struct nk_context *ctx, float height)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    nk_panel_layout(ctx, win, height, 1);\n    layout->row.type = NK_LAYOUT_TEMPLATE;\n    layout->row.columns = 0;\n    layout->row.ratio = 0;\n    layout->row.item_width = 0;\n    layout->row.item_height = 0;\n    layout->row.item_offset = 0;\n    layout->row.filled = 0;\n    layout->row.item.x = 0;\n    layout->row.item.y = 0;\n    layout->row.item.w = 0;\n    layout->row.item.h = 0;\n}\nNK_API void\nnk_layout_row_template_push_dynamic(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);\n    NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);\n    if (layout->row.type != NK_LAYOUT_TEMPLATE) return;\n    if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;\n    layout->row.templates[layout->row.columns++] = -1.0f;\n}\nNK_API void\nnk_layout_row_template_push_variable(struct nk_context *ctx, float min_width)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);\n    NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);\n    if (layout->row.type != NK_LAYOUT_TEMPLATE) return;\n    if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;\n    layout->row.templates[layout->row.columns++] = -min_width;\n}\nNK_API void\nnk_layout_row_template_push_static(struct nk_context *ctx, float width)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);\n    NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);\n    if (layout->row.type != NK_LAYOUT_TEMPLATE) return;\n    if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;\n    layout->row.templates[layout->row.columns++] = width;\n}\nNK_API void\nnk_layout_row_template_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    int i = 0;\n    int variable_count = 0;\n    int min_variable_count = 0;\n    float min_fixed_width = 0.0f;\n    float total_fixed_width = 0.0f;\n    float max_variable_width = 0.0f;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);\n    if (layout->row.type != NK_LAYOUT_TEMPLATE) return;\n    for (i = 0; i < layout->row.columns; ++i) {\n        float width = layout->row.templates[i];\n        if (width >= 0.0f) {\n            total_fixed_width += width;\n            min_fixed_width += width;\n        } else if (width < -1.0f) {\n            width = -width;\n            total_fixed_width += width;\n            max_variable_width = NK_MAX(max_variable_width, width);\n            variable_count++;\n        } else {\n            min_variable_count++;\n            variable_count++;\n        }\n    }\n    if (variable_count) {\n        float space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,\n                            layout->bounds.w, layout->row.columns);\n        float var_width = (NK_MAX(space-min_fixed_width,0.0f)) / (float)variable_count;\n        int enough_space = var_width >= max_variable_width;\n        if (!enough_space)\n            var_width = (NK_MAX(space-total_fixed_width,0)) / (float)min_variable_count;\n        for (i = 0; i < layout->row.columns; ++i) {\n            float *width = &layout->row.templates[i];\n            *width = (*width >= 0.0f)? *width: (*width < -1.0f && !enough_space)? -(*width): var_width;\n        }\n    }\n}\nNK_API void\nnk_layout_space_begin(struct nk_context *ctx, enum nk_layout_format fmt,\n    float height, int widget_count)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    nk_panel_layout(ctx, win, height, widget_count);\n    if (fmt == NK_STATIC)\n        layout->row.type = NK_LAYOUT_STATIC_FREE;\n    else layout->row.type = NK_LAYOUT_DYNAMIC_FREE;\n\n    layout->row.ratio = 0;\n    layout->row.filled = 0;\n    layout->row.item_width = 0;\n    layout->row.item_offset = 0;\n}\nNK_API void\nnk_layout_space_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    layout->row.item_width = 0;\n    layout->row.item_height = 0;\n    layout->row.item_offset = 0;\n    nk_zero(&layout->row.item, sizeof(layout->row.item));\n}\nNK_API void\nnk_layout_space_push(struct nk_context *ctx, struct nk_rect rect)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    layout->row.item = rect;\n}\nNK_API struct nk_rect\nnk_layout_space_bounds(const struct nk_context *ctx)\n{\n    struct nk_rect ret;\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    win = ctx->current;\n    layout = win->layout;\n\n    ret.x = layout->clip.x;\n    ret.y = layout->clip.y;\n    ret.w = layout->clip.w;\n    ret.h = layout->row.height;\n    return ret;\n}\nNK_API struct nk_rect\nnk_layout_widget_bounds(const struct nk_context *ctx)\n{\n    struct nk_rect ret;\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    win = ctx->current;\n    layout = win->layout;\n\n    ret.x = layout->at_x;\n    ret.y = layout->at_y;\n    ret.w = layout->bounds.w - NK_MAX(layout->at_x - layout->bounds.x,0);\n    ret.h = layout->row.height;\n    return ret;\n}\nNK_API struct nk_vec2\nnk_layout_space_to_screen(const struct nk_context *ctx, struct nk_vec2 ret)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    win = ctx->current;\n    layout = win->layout;\n\n    ret.x += layout->at_x - (float)*layout->offset_x;\n    ret.y += layout->at_y - (float)*layout->offset_y;\n    return ret;\n}\nNK_API struct nk_vec2\nnk_layout_space_to_local(const struct nk_context *ctx, struct nk_vec2 ret)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    win = ctx->current;\n    layout = win->layout;\n\n    ret.x += -layout->at_x + (float)*layout->offset_x;\n    ret.y += -layout->at_y + (float)*layout->offset_y;\n    return ret;\n}\nNK_API struct nk_rect\nnk_layout_space_rect_to_screen(const struct nk_context *ctx, struct nk_rect ret)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    win = ctx->current;\n    layout = win->layout;\n\n    ret.x += layout->at_x - (float)*layout->offset_x;\n    ret.y += layout->at_y - (float)*layout->offset_y;\n    return ret;\n}\nNK_API struct nk_rect\nnk_layout_space_rect_to_local(const struct nk_context *ctx, struct nk_rect ret)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    win = ctx->current;\n    layout = win->layout;\n\n    ret.x += -layout->at_x + (float)*layout->offset_x;\n    ret.y += -layout->at_y + (float)*layout->offset_y;\n    return ret;\n}\nNK_LIB void\nnk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win)\n{\n    struct nk_panel *layout = win->layout;\n    struct nk_vec2 spacing = ctx->style.window.spacing;\n    const float row_height = layout->row.height - spacing.y;\n    nk_panel_layout(ctx, win, row_height, layout->row.columns);\n}\nNK_LIB void\nnk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx,\n    struct nk_window *win, int modify)\n{\n    struct nk_panel *layout;\n    const struct nk_style *style;\n\n    struct nk_vec2 spacing;\n\n    float item_offset = 0;\n    float item_width = 0;\n    float item_spacing = 0;\n    float panel_space = 0;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    style = &ctx->style;\n    NK_ASSERT(bounds);\n\n    spacing = style->window.spacing;\n    panel_space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,\n                                            layout->bounds.w, layout->row.columns);\n\n    #define NK_FRAC(x) (x - (float)(int)nk_roundf(x)) /* will be used to remove fookin gaps */\n    /* calculate the width of one item inside the current layout space */\n    switch (layout->row.type) {\n    case NK_LAYOUT_DYNAMIC_FIXED: {\n        /* scaling fixed size widgets item width */\n        float w = NK_MAX(1.0f,panel_space) / (float)layout->row.columns;\n        item_offset = (float)layout->row.index * w;\n        item_width = w + NK_FRAC(item_offset);\n        item_spacing = (float)layout->row.index * spacing.x;\n    } break;\n    case NK_LAYOUT_DYNAMIC_ROW: {\n        /* scaling single ratio widget width */\n        float w = layout->row.item_width * panel_space;\n        item_offset = layout->row.item_offset;\n        item_width = w + NK_FRAC(item_offset);\n        item_spacing = 0;\n\n        if (modify) {\n            layout->row.item_offset += w + spacing.x;\n            layout->row.filled += layout->row.item_width;\n            layout->row.index = 0;\n        }\n    } break;\n    case NK_LAYOUT_DYNAMIC_FREE: {\n        /* panel width depended free widget placing */\n        bounds->x = layout->at_x + (layout->bounds.w * layout->row.item.x);\n        bounds->x -= (float)*layout->offset_x;\n        bounds->y = layout->at_y + (layout->row.height * layout->row.item.y);\n        bounds->y -= (float)*layout->offset_y;\n        bounds->w = layout->bounds.w  * layout->row.item.w + NK_FRAC(bounds->x);\n        bounds->h = layout->row.height * layout->row.item.h + NK_FRAC(bounds->y);\n        return;\n    }\n    case NK_LAYOUT_DYNAMIC: {\n        /* scaling arrays of panel width ratios for every widget */\n        float ratio, w;\n        NK_ASSERT(layout->row.ratio);\n        ratio = (layout->row.ratio[layout->row.index] < 0) ?\n            layout->row.item_width : layout->row.ratio[layout->row.index];\n\n        w = (ratio * panel_space);\n        item_spacing = (float)layout->row.index * spacing.x;\n        item_offset = layout->row.item_offset;\n        item_width = w + NK_FRAC(item_offset);\n\n        if (modify) {\n            layout->row.item_offset += w;\n            layout->row.filled += ratio;\n        }\n    } break;\n    case NK_LAYOUT_STATIC_FIXED: {\n        /* non-scaling fixed widgets item width */\n        item_width = layout->row.item_width;\n        item_offset = (float)layout->row.index * item_width;\n        item_spacing = (float)layout->row.index * spacing.x;\n    } break;\n    case NK_LAYOUT_STATIC_ROW: {\n        /* scaling single ratio widget width */\n        item_width = layout->row.item_width;\n        item_offset = layout->row.item_offset;\n        item_spacing = (float)layout->row.index * spacing.x;\n        if (modify) layout->row.item_offset += item_width;\n    } break;\n    case NK_LAYOUT_STATIC_FREE: {\n        /* free widget placing */\n        bounds->x = layout->at_x + layout->row.item.x;\n        bounds->w = layout->row.item.w;\n        if (((bounds->x + bounds->w) > layout->max_x) && modify)\n            layout->max_x = (bounds->x + bounds->w);\n        bounds->x -= (float)*layout->offset_x;\n        bounds->y = layout->at_y + layout->row.item.y;\n        bounds->y -= (float)*layout->offset_y;\n        bounds->h = layout->row.item.h;\n        return;\n    }\n    case NK_LAYOUT_STATIC: {\n        /* non-scaling array of panel pixel width for every widget */\n        item_spacing = (float)layout->row.index * spacing.x;\n        item_width = layout->row.ratio[layout->row.index];\n        item_offset = layout->row.item_offset;\n        if (modify) layout->row.item_offset += item_width;\n    } break;\n    case NK_LAYOUT_TEMPLATE: {\n        /* stretchy row layout with combined dynamic/static widget width*/\n        float w;\n        NK_ASSERT(layout->row.index < layout->row.columns);\n        NK_ASSERT(layout->row.index < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);\n        w = layout->row.templates[layout->row.index];\n        item_offset = layout->row.item_offset;\n        item_width = w + NK_FRAC(item_offset);\n        item_spacing = (float)layout->row.index * spacing.x;\n        if (modify) layout->row.item_offset += w;\n    } break;\n    #undef NK_FRAC\n    default: NK_ASSERT(0); break;\n    };\n\n    /* set the bounds of the newly allocated widget */\n    bounds->w = item_width;\n    bounds->h = layout->row.height - spacing.y;\n    bounds->y = layout->at_y - (float)*layout->offset_y;\n    bounds->x = layout->at_x + item_offset + item_spacing;\n    if (((bounds->x + bounds->w) > layout->max_x) && modify)\n        layout->max_x = bounds->x + bounds->w;\n    bounds->x -= (float)*layout->offset_x;\n}\nNK_LIB void\nnk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    /* check if the end of the row has been hit and begin new row if so */\n    win = ctx->current;\n    layout = win->layout;\n    if (layout->row.index >= layout->row.columns)\n        nk_panel_alloc_row(ctx, win);\n\n    /* calculate widget position and size */\n    nk_layout_widget_space(bounds, ctx, win, nk_true);\n    layout->row.index++;\n}\nNK_LIB void\nnk_layout_peek(struct nk_rect *bounds, const struct nk_context *ctx)\n{\n    float y;\n    int index;\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) {\n        *bounds = nk_rect(0,0,0,0);\n        return;\n    }\n\n    win = ctx->current;\n    layout = win->layout;\n    y = layout->at_y;\n    index = layout->row.index;\n    if (layout->row.index >= layout->row.columns) {\n        layout->at_y += layout->row.height;\n        layout->row.index = 0;\n    }\n    nk_layout_widget_space(bounds, ctx, win, nk_false);\n    if (!layout->row.index) {\n        bounds->x -= layout->row.item_offset;\n    }\n    layout->at_y = y;\n    layout->row.index = index;\n}\nNK_API void\nnk_spacer(struct nk_context *ctx )\n{\n    struct nk_rect dummy_rect = { 0, 0, 0, 0 };\n    nk_panel_alloc_space( &dummy_rect, ctx );\n}\n\n\n\n\n/* ===============================================================\n *\n *                              TREE\n *\n * ===============================================================*/\nNK_INTERN int\nnk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image *img, const char *title, enum nk_collapse_states *state)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_style *style;\n    struct nk_command_buffer *out;\n    const struct nk_input *in;\n    const struct nk_style_button *button;\n    enum nk_symbol_type symbol;\n    float row_height;\n\n    struct nk_vec2 item_spacing;\n    struct nk_rect header = {0,0,0,0};\n    struct nk_rect sym = {0,0,0,0};\n    struct nk_text text;\n\n    nk_flags ws = 0;\n    enum nk_widget_layout_states widget_state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    /* cache some data */\n    win = ctx->current;\n    layout = win->layout;\n    out = &win->buffer;\n    style = &ctx->style;\n    item_spacing = style->window.spacing;\n\n    /* calculate header bounds and draw background */\n    row_height = style->font->height + 2 * style->tab.padding.y;\n    nk_layout_set_min_row_height(ctx, row_height);\n    nk_layout_row_dynamic(ctx, row_height, 1);\n    nk_layout_reset_min_row_height(ctx);\n\n    widget_state = nk_widget(&header, ctx);\n    if (type == NK_TREE_TAB) {\n        const struct nk_style_item *background = &style->tab.background;\n\n        switch(background->type) {\n            case NK_STYLE_ITEM_IMAGE:\n                nk_draw_image(out, header, &background->data.image, nk_rgb_factor(nk_white, style->tab.color_factor));\n                break;\n            case NK_STYLE_ITEM_NINE_SLICE:\n                nk_draw_nine_slice(out, header, &background->data.slice, nk_rgb_factor(nk_white, style->tab.color_factor));\n                break;\n            case NK_STYLE_ITEM_COLOR:\n                nk_fill_rect(out, header, 0, nk_rgb_factor(style->tab.border_color, style->tab.color_factor));\n                nk_fill_rect(out, nk_shrink_rect(header, style->tab.border),\n                    style->tab.rounding, nk_rgb_factor(background->data.color, style->tab.color_factor));\n                break;\n        }\n    } else text.background = style->window.background;\n\n    /* update node state */\n    in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0;\n    in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0;\n    if (nk_button_behavior(&ws, header, in, NK_BUTTON_DEFAULT))\n        *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;\n\n    /* select correct button style */\n    if (*state == NK_MAXIMIZED) {\n        symbol = style->tab.sym_maximize;\n        if (type == NK_TREE_TAB)\n            button = &style->tab.tab_maximize_button;\n        else button = &style->tab.node_maximize_button;\n    } else {\n        symbol = style->tab.sym_minimize;\n        if (type == NK_TREE_TAB)\n            button = &style->tab.tab_minimize_button;\n        else button = &style->tab.node_minimize_button;\n    }\n\n    {/* draw triangle button */\n    sym.w = sym.h = style->font->height;\n    sym.y = header.y + style->tab.padding.y;\n    sym.x = header.x + style->tab.padding.x;\n    nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT,\n        button, 0, style->font);\n\n    if (img) {\n        /* draw optional image icon */\n        sym.x = sym.x + sym.w + 4 * item_spacing.x;\n        nk_draw_image(&win->buffer, sym, img, nk_white);\n        sym.w = style->font->height + style->tab.spacing.x;}\n    }\n\n    {/* draw label */\n    struct nk_rect label;\n    header.w = NK_MAX(header.w, sym.w + item_spacing.x);\n    label.x = sym.x + sym.w + item_spacing.x;\n    label.y = sym.y;\n    label.w = header.w - (sym.w + item_spacing.y + style->tab.indent);\n    label.h = style->font->height;\n    text.text = nk_rgb_factor(style->tab.text, style->tab.color_factor);\n    text.padding = nk_vec2(0,0);\n    nk_widget_text(out, label, title, nk_strlen(title), &text,\n        NK_TEXT_LEFT, style->font);}\n\n    /* increase x-axis cursor widget position pointer */\n    if (*state == NK_MAXIMIZED) {\n        layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent;\n        layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent);\n        layout->bounds.w -= (style->tab.indent + style->window.padding.x);\n        layout->row.tree_depth++;\n        return nk_true;\n    } else return nk_false;\n}\nNK_INTERN int\nnk_tree_base(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image *img, const char *title, enum nk_collapse_states initial_state,\n    const char *hash, int len, int line)\n{\n    struct nk_window *win = ctx->current;\n    int title_len = 0;\n    nk_hash tree_hash = 0;\n    nk_uint *state = 0;\n\n    /* retrieve tree state from internal widget state tables */\n    if (!hash) {\n        title_len = (int)nk_strlen(title);\n        tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line);\n    } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line);\n    state = nk_find_value(win, tree_hash);\n    if (!state) {\n        state = nk_add_value(ctx, win, tree_hash, 0);\n        *state = initial_state;\n    }\n    return nk_tree_state_base(ctx, type, img, title, (enum nk_collapse_states*)state);\n}\nNK_API nk_bool\nnk_tree_state_push(struct nk_context *ctx, enum nk_tree_type type,\n    const char *title, enum nk_collapse_states *state)\n{\n    return nk_tree_state_base(ctx, type, 0, title, state);\n}\nNK_API nk_bool\nnk_tree_state_image_push(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image img, const char *title, enum nk_collapse_states *state)\n{\n    return nk_tree_state_base(ctx, type, &img, title, state);\n}\nNK_API void\nnk_tree_state_pop(struct nk_context *ctx)\n{\n    struct nk_window *win = 0;\n    struct nk_panel *layout = 0;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    layout->at_x -= ctx->style.tab.indent + (float)*layout->offset_x;\n    layout->bounds.w += ctx->style.tab.indent + ctx->style.window.padding.x;\n    NK_ASSERT(layout->row.tree_depth);\n    layout->row.tree_depth--;\n}\nNK_API nk_bool\nnk_tree_push_hashed(struct nk_context *ctx, enum nk_tree_type type,\n    const char *title, enum nk_collapse_states initial_state,\n    const char *hash, int len, int line)\n{\n    return nk_tree_base(ctx, type, 0, title, initial_state, hash, len, line);\n}\nNK_API nk_bool\nnk_tree_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image img, const char *title, enum nk_collapse_states initial_state,\n    const char *hash, int len,int seed)\n{\n    return nk_tree_base(ctx, type, &img, title, initial_state, hash, len, seed);\n}\nNK_API void\nnk_tree_pop(struct nk_context *ctx)\n{\n    nk_tree_state_pop(ctx);\n}\nNK_INTERN int\nnk_tree_element_image_push_hashed_base(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image *img, const char *title, int title_len,\n    enum nk_collapse_states *state, nk_bool *selected)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_style *style;\n    struct nk_command_buffer *out;\n    const struct nk_input *in;\n    const struct nk_style_button *button;\n    enum nk_symbol_type symbol;\n    float row_height;\n    struct nk_vec2 padding;\n\n    int text_len;\n    float text_width;\n\n    struct nk_vec2 item_spacing;\n    struct nk_rect header = {0,0,0,0};\n    struct nk_rect sym = {0,0,0,0};\n\n    nk_flags ws = 0;\n    enum nk_widget_layout_states widget_state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    /* cache some data */\n    win = ctx->current;\n    layout = win->layout;\n    out = &win->buffer;\n    style = &ctx->style;\n    item_spacing = style->window.spacing;\n    padding = style->selectable.padding;\n\n    /* calculate header bounds and draw background */\n    row_height = style->font->height + 2 * style->tab.padding.y;\n    nk_layout_set_min_row_height(ctx, row_height);\n    nk_layout_row_dynamic(ctx, row_height, 1);\n    nk_layout_reset_min_row_height(ctx);\n\n    widget_state = nk_widget(&header, ctx);\n    if (type == NK_TREE_TAB) {\n        const struct nk_style_item *background = &style->tab.background;\n\n        switch (background->type) {\n            case NK_STYLE_ITEM_IMAGE:\n                nk_draw_image(out, header, &background->data.image, nk_rgb_factor(nk_white, style->tab.color_factor));\n                break;\n            case NK_STYLE_ITEM_NINE_SLICE:\n                nk_draw_nine_slice(out, header, &background->data.slice, nk_rgb_factor(nk_white, style->tab.color_factor));\n                break;\n            case NK_STYLE_ITEM_COLOR:\n                nk_fill_rect(out, header, 0, nk_rgb_factor(style->tab.border_color, style->tab.color_factor));\n                nk_fill_rect(out, nk_shrink_rect(header, style->tab.border),\n                    style->tab.rounding, nk_rgb_factor(background->data.color, style->tab.color_factor));\n\n                break;\n        }\n    }\n\n    in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0;\n    in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0;\n\n    /* select correct button style */\n    if (*state == NK_MAXIMIZED) {\n        symbol = style->tab.sym_maximize;\n        if (type == NK_TREE_TAB)\n            button = &style->tab.tab_maximize_button;\n        else button = &style->tab.node_maximize_button;\n    } else {\n        symbol = style->tab.sym_minimize;\n        if (type == NK_TREE_TAB)\n            button = &style->tab.tab_minimize_button;\n        else button = &style->tab.node_minimize_button;\n    }\n    {/* draw triangle button */\n    sym.w = sym.h = style->font->height;\n    sym.y = header.y + style->tab.padding.y;\n    sym.x = header.x + style->tab.padding.x;\n    if (nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT, button, in, style->font))\n        *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;}\n\n    /* draw label */\n    {nk_flags dummy = 0;\n    struct nk_rect label;\n    /* calculate size of the text and tooltip */\n    text_len = nk_strlen(title);\n    text_width = style->font->width(style->font->userdata, style->font->height, title, text_len);\n    text_width += (4 * padding.x);\n\n    header.w = NK_MAX(header.w, sym.w + item_spacing.x);\n    label.x = sym.x + sym.w + item_spacing.x;\n    label.y = sym.y;\n    label.w = NK_MIN(header.w - (sym.w + item_spacing.y + style->tab.indent), text_width);\n    label.h = style->font->height;\n\n    if (img) {\n        nk_do_selectable_image(&dummy, &win->buffer, label, title, title_len, NK_TEXT_LEFT,\n            selected, img, &style->selectable, in, style->font);\n    } else nk_do_selectable(&dummy, &win->buffer, label, title, title_len, NK_TEXT_LEFT,\n            selected, &style->selectable, in, style->font);\n    }\n    /* increase x-axis cursor widget position pointer */\n    if (*state == NK_MAXIMIZED) {\n        layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent;\n        layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent);\n        layout->bounds.w -= (style->tab.indent + style->window.padding.x);\n        layout->row.tree_depth++;\n        return nk_true;\n    } else return nk_false;\n}\nNK_INTERN int\nnk_tree_element_base(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image *img, const char *title, enum nk_collapse_states initial_state,\n    nk_bool *selected, const char *hash, int len, int line)\n{\n    struct nk_window *win = ctx->current;\n    int title_len = 0;\n    nk_hash tree_hash = 0;\n    nk_uint *state = 0;\n\n    /* retrieve tree state from internal widget state tables */\n    if (!hash) {\n        title_len = (int)nk_strlen(title);\n        tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line);\n    } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line);\n    state = nk_find_value(win, tree_hash);\n    if (!state) {\n        state = nk_add_value(ctx, win, tree_hash, 0);\n        *state = initial_state;\n    } return nk_tree_element_image_push_hashed_base(ctx, type, img, title,\n        nk_strlen(title), (enum nk_collapse_states*)state, selected);\n}\nNK_API nk_bool\nnk_tree_element_push_hashed(struct nk_context *ctx, enum nk_tree_type type,\n    const char *title, enum nk_collapse_states initial_state,\n    nk_bool *selected, const char *hash, int len, int seed)\n{\n    return nk_tree_element_base(ctx, type, 0, title, initial_state, selected, hash, len, seed);\n}\nNK_API nk_bool\nnk_tree_element_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image img, const char *title, enum nk_collapse_states initial_state,\n    nk_bool *selected, const char *hash, int len,int seed)\n{\n    return nk_tree_element_base(ctx, type, &img, title, initial_state, selected, hash, len, seed);\n}\nNK_API void\nnk_tree_element_pop(struct nk_context *ctx)\n{\n    nk_tree_state_pop(ctx);\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                          GROUP\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_group_scrolled_offset_begin(struct nk_context *ctx,\n    nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags)\n{\n    struct nk_rect bounds;\n    struct nk_window panel;\n    struct nk_window *win;\n\n    win = ctx->current;\n    nk_panel_alloc_space(&bounds, ctx);\n    {const struct nk_rect *c = &win->layout->clip;\n    if (!NK_INTERSECT(c->x, c->y, c->w, c->h, bounds.x, bounds.y, bounds.w, bounds.h) &&\n        !(flags & NK_WINDOW_MOVABLE)) {\n        return 0;\n    }}\n    if (win->flags & NK_WINDOW_ROM)\n        flags |= NK_WINDOW_ROM;\n\n    /* initialize a fake window to create the panel from */\n    nk_zero(&panel, sizeof(panel));\n    panel.bounds = bounds;\n    panel.flags = flags;\n    panel.scrollbar.x = *x_offset;\n    panel.scrollbar.y = *y_offset;\n    panel.buffer = win->buffer;\n    panel.layout = (struct nk_panel*)nk_create_panel(ctx);\n    ctx->current = &panel;\n    nk_panel_begin(ctx, (flags & NK_WINDOW_TITLE) ? title: 0, NK_PANEL_GROUP);\n\n    win->buffer = panel.buffer;\n    win->buffer.clip = panel.layout->clip;\n    panel.layout->offset_x = x_offset;\n    panel.layout->offset_y = y_offset;\n    panel.layout->parent = win->layout;\n    win->layout = panel.layout;\n\n    ctx->current = win;\n    if ((panel.layout->flags & NK_WINDOW_CLOSED) ||\n        (panel.layout->flags & NK_WINDOW_MINIMIZED))\n    {\n        nk_flags f = panel.layout->flags;\n        nk_group_scrolled_end(ctx);\n        if (f & NK_WINDOW_CLOSED)\n            return NK_WINDOW_CLOSED;\n        if (f & NK_WINDOW_MINIMIZED)\n            return NK_WINDOW_MINIMIZED;\n    }\n    return 1;\n}\nNK_API void\nnk_group_scrolled_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *parent;\n    struct nk_panel *g;\n\n    struct nk_rect clip;\n    struct nk_window pan;\n    struct nk_vec2 panel_padding;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return;\n\n    /* make sure nk_group_begin was called correctly */\n    NK_ASSERT(ctx->current);\n    win = ctx->current;\n    NK_ASSERT(win->layout);\n    g = win->layout;\n    NK_ASSERT(g->parent);\n    parent = g->parent;\n\n    /* dummy window */\n    nk_zero_struct(pan);\n    panel_padding = nk_panel_get_padding(&ctx->style, NK_PANEL_GROUP);\n    pan.bounds.y = g->bounds.y - (g->header_height + g->menu.h);\n    pan.bounds.x = g->bounds.x - panel_padding.x;\n    pan.bounds.w = g->bounds.w + 2 * panel_padding.x;\n    pan.bounds.h = g->bounds.h + g->header_height + g->menu.h;\n    if (g->flags & NK_WINDOW_BORDER) {\n        pan.bounds.x -= g->border;\n        pan.bounds.y -= g->border;\n        pan.bounds.w += 2*g->border;\n        pan.bounds.h += 2*g->border;\n    }\n    if (!(g->flags & NK_WINDOW_NO_SCROLLBAR)) {\n        pan.bounds.w += ctx->style.window.scrollbar_size.x;\n        pan.bounds.h += ctx->style.window.scrollbar_size.y;\n    }\n    pan.scrollbar.x = *g->offset_x;\n    pan.scrollbar.y = *g->offset_y;\n    pan.flags = g->flags;\n    pan.buffer = win->buffer;\n    pan.layout = g;\n    pan.parent = win;\n    ctx->current = &pan;\n\n    /* make sure group has correct clipping rectangle */\n    nk_unify(&clip, &parent->clip, pan.bounds.x, pan.bounds.y,\n        pan.bounds.x + pan.bounds.w, pan.bounds.y + pan.bounds.h + panel_padding.x);\n    nk_push_scissor(&pan.buffer, clip);\n    nk_end(ctx);\n\n    win->buffer = pan.buffer;\n    nk_push_scissor(&win->buffer, parent->clip);\n    ctx->current = win;\n    win->layout = parent;\n    g->bounds = pan.bounds;\n    return;\n}\nNK_API nk_bool\nnk_group_scrolled_begin(struct nk_context *ctx,\n    struct nk_scroll *scroll, const char *title, nk_flags flags)\n{\n    return nk_group_scrolled_offset_begin(ctx, &scroll->x, &scroll->y, title, flags);\n}\nNK_API nk_bool\nnk_group_begin_titled(struct nk_context *ctx, const char *id,\n    const char *title, nk_flags flags)\n{\n    int id_len;\n    nk_hash id_hash;\n    struct nk_window *win;\n    nk_uint *x_offset;\n    nk_uint *y_offset;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(id);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !id)\n        return 0;\n\n    /* find persistent group scrollbar value */\n    win = ctx->current;\n    id_len = (int)nk_strlen(id);\n    id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP);\n    x_offset = nk_find_value(win, id_hash);\n    if (!x_offset) {\n        x_offset = nk_add_value(ctx, win, id_hash, 0);\n        y_offset = nk_add_value(ctx, win, id_hash+1, 0);\n\n        NK_ASSERT(x_offset);\n        NK_ASSERT(y_offset);\n        if (!x_offset || !y_offset) return 0;\n        *x_offset = *y_offset = 0;\n    } else if (!(y_offset = nk_find_value(win, id_hash+1))) {\n        y_offset = nk_add_value(ctx, win, id_hash+1, 0);\n        NK_ASSERT(y_offset);\n        if (!y_offset) return 0;\n        *x_offset = *y_offset = 0; /* I think this covers the degenerate case */\n    }\n\n    return nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);\n}\nNK_API nk_bool\nnk_group_begin(struct nk_context *ctx, const char *title, nk_flags flags)\n{\n    return nk_group_begin_titled(ctx, title, title, flags);\n}\nNK_API void\nnk_group_end(struct nk_context *ctx)\n{\n    nk_group_scrolled_end(ctx);\n}\nNK_API void\nnk_group_get_scroll(struct nk_context *ctx, const char *id, nk_uint *x_offset, nk_uint *y_offset)\n{\n    int id_len;\n    nk_hash id_hash;\n    struct nk_window *win;\n    nk_uint *x_offset_ptr;\n    nk_uint *y_offset_ptr;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(id);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !id)\n        return;\n\n    /* find persistent group scrollbar value */\n    win = ctx->current;\n    id_len = (int)nk_strlen(id);\n    id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP);\n    x_offset_ptr = nk_find_value(win, id_hash);\n    if (!x_offset_ptr) {\n        x_offset_ptr = nk_add_value(ctx, win, id_hash, 0);\n        y_offset_ptr = nk_add_value(ctx, win, id_hash+1, 0);\n\n        NK_ASSERT(x_offset_ptr);\n        NK_ASSERT(y_offset_ptr);\n        if (!x_offset_ptr || !y_offset_ptr) return;\n        *x_offset_ptr = *y_offset_ptr = 0;\n    } else if (!(y_offset_ptr = nk_find_value(win, id_hash+1))) {\n        y_offset_ptr = nk_add_value(ctx, win, id_hash+1, 0);\n        NK_ASSERT(y_offset_ptr);\n        if (!y_offset_ptr) return;\n        *x_offset_ptr = *y_offset_ptr = 0;\n    }\n    if (x_offset)\n      *x_offset = *x_offset_ptr;\n    if (y_offset)\n      *y_offset = *y_offset_ptr;\n}\nNK_API void\nnk_group_set_scroll(struct nk_context *ctx, const char *id, nk_uint x_offset, nk_uint y_offset)\n{\n    int id_len;\n    nk_hash id_hash;\n    struct nk_window *win;\n    nk_uint *x_offset_ptr;\n    nk_uint *y_offset_ptr;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(id);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !id)\n        return;\n\n    /* find persistent group scrollbar value */\n    win = ctx->current;\n    id_len = (int)nk_strlen(id);\n    id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP);\n    x_offset_ptr = nk_find_value(win, id_hash);\n    if (!x_offset_ptr) {\n        x_offset_ptr = nk_add_value(ctx, win, id_hash, 0);\n        y_offset_ptr = nk_add_value(ctx, win, id_hash+1, 0);\n\n        NK_ASSERT(x_offset_ptr);\n        NK_ASSERT(y_offset_ptr);\n        if (!x_offset_ptr || !y_offset_ptr) return;\n        *x_offset_ptr = *y_offset_ptr = 0;\n    } else if (!(y_offset_ptr = nk_find_value(win, id_hash+1))) {\n        NK_ASSERT(y_offset_ptr);\n        if (!y_offset_ptr) return;\n        *x_offset_ptr = *y_offset_ptr = 0;\n    }\n    *x_offset_ptr = x_offset;\n    *y_offset_ptr = y_offset;\n}\n\n\n\n\n/* ===============================================================\n *\n *                          LIST VIEW\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_list_view_begin(struct nk_context *ctx, struct nk_list_view *view,\n    const char *title, nk_flags flags, int row_height, int row_count)\n{\n    int title_len;\n    nk_hash title_hash;\n    nk_uint *x_offset;\n    nk_uint *y_offset;\n\n    int result;\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_style *style;\n    struct nk_vec2 item_spacing;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(view);\n    NK_ASSERT(title);\n    if (!ctx || !view || !title) return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    item_spacing = style->window.spacing;\n    row_height += NK_MAX(0, (int)item_spacing.y);\n\n    /* find persistent list view scrollbar offset */\n    title_len = (int)nk_strlen(title);\n    title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP);\n    x_offset = nk_find_value(win, title_hash);\n    if (!x_offset) {\n        x_offset = nk_add_value(ctx, win, title_hash, 0);\n        y_offset = nk_add_value(ctx, win, title_hash+1, 0);\n\n        NK_ASSERT(x_offset);\n        NK_ASSERT(y_offset);\n        if (!x_offset || !y_offset) return 0;\n        *x_offset = *y_offset = 0;\n    } else if (!(y_offset = nk_find_value(win, title_hash+1))) {\n        NK_ASSERT(y_offset);\n        if (!y_offset) return 0;\n        *x_offset = *y_offset = 0;\n    }\n    view->scroll_value = *y_offset;\n    view->scroll_pointer = y_offset;\n\n    *y_offset = 0;\n    result = nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);\n    win = ctx->current;\n    layout = win->layout;\n\n    view->total_height = row_height * NK_MAX(row_count,1);\n    view->begin = (int)NK_MAX(((float)view->scroll_value / (float)row_height), 0.0f);\n    view->count = (int)NK_MAX(nk_iceilf((layout->clip.h)/(float)row_height),0);\n    view->count = NK_MIN(view->count, row_count - view->begin);\n    view->end = view->begin + view->count;\n    view->ctx = ctx;\n    return result;\n}\nNK_API void\nnk_list_view_end(struct nk_list_view *view)\n{\n    struct nk_context *ctx;\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(view);\n    NK_ASSERT(view->ctx);\n    NK_ASSERT(view->scroll_pointer);\n    if (!view || !view->ctx) return;\n\n    ctx = view->ctx;\n    win = ctx->current;\n    layout = win->layout;\n    layout->at_y = layout->bounds.y + (float)view->total_height;\n    *view->scroll_pointer = *view->scroll_pointer + view->scroll_value;\n    nk_group_end(view->ctx);\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                              WIDGET\n *\n * ===============================================================*/\nNK_API struct nk_rect\nnk_widget_bounds(const struct nk_context *ctx)\n{\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return nk_rect(0,0,0,0);\n    nk_layout_peek(&bounds, ctx);\n    return bounds;\n}\nNK_API struct nk_vec2\nnk_widget_position(const struct nk_context *ctx)\n{\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return nk_vec2(0,0);\n\n    nk_layout_peek(&bounds, ctx);\n    return nk_vec2(bounds.x, bounds.y);\n}\nNK_API struct nk_vec2\nnk_widget_size(const struct nk_context *ctx)\n{\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return nk_vec2(0,0);\n\n    nk_layout_peek(&bounds, ctx);\n    return nk_vec2(bounds.w, bounds.h);\n}\nNK_API float\nnk_widget_width(const struct nk_context *ctx)\n{\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return 0;\n\n    nk_layout_peek(&bounds, ctx);\n    return bounds.w;\n}\nNK_API float\nnk_widget_height(const struct nk_context *ctx)\n{\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return 0;\n\n    nk_layout_peek(&bounds, ctx);\n    return bounds.h;\n}\nNK_API nk_bool\nnk_widget_is_hovered(const struct nk_context *ctx)\n{\n    struct nk_rect c, v;\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || (ctx->active != ctx->current && !((int)ctx->current->layout->type & (int)NK_PANEL_SET_POPUP)))\n        return 0;\n\n    c = ctx->current->layout->clip;\n    c.x = (float)((int)c.x);\n    c.y = (float)((int)c.y);\n    c.w = (float)((int)c.w);\n    c.h = (float)((int)c.h);\n\n    nk_layout_peek(&bounds, ctx);\n    nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);\n    if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))\n        return 0;\n    return nk_input_is_mouse_hovering_rect(&ctx->input, bounds);\n}\nNK_API nk_bool\nnk_widget_is_mouse_clicked(const struct nk_context *ctx, enum nk_buttons btn)\n{\n    struct nk_rect c, v;\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || (ctx->active != ctx->current && !((int)ctx->current->layout->type & (int)NK_PANEL_SET_POPUP)))\n        return 0;\n\n    c = ctx->current->layout->clip;\n    c.x = (float)((int)c.x);\n    c.y = (float)((int)c.y);\n    c.w = (float)((int)c.w);\n    c.h = (float)((int)c.h);\n\n    nk_layout_peek(&bounds, ctx);\n    nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);\n    if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))\n        return 0;\n    return nk_input_mouse_clicked(&ctx->input, btn, bounds);\n}\nNK_API nk_bool\nnk_widget_has_mouse_click_down(const struct nk_context *ctx, enum nk_buttons btn, nk_bool down)\n{\n    struct nk_rect c, v;\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || (ctx->active != ctx->current && !((int)ctx->current->layout->type & (int)NK_PANEL_SET_POPUP)))\n        return 0;\n\n    c = ctx->current->layout->clip;\n    c.x = (float)((int)c.x);\n    c.y = (float)((int)c.y);\n    c.w = (float)((int)c.w);\n    c.h = (float)((int)c.h);\n\n    nk_layout_peek(&bounds, ctx);\n    nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);\n    if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))\n        return 0;\n    return nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down);\n}\nNK_API enum nk_widget_layout_states\nnk_widget(struct nk_rect *bounds, const struct nk_context *ctx)\n{\n    struct nk_rect c, v;\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return NK_WIDGET_INVALID;\n\n    /* allocate space and check if the widget needs to be updated and drawn */\n    nk_panel_alloc_space(bounds, ctx);\n    win = ctx->current;\n    layout = win->layout;\n    in = &ctx->input;\n    c = layout->clip;\n\n    /*  if one of these triggers you forgot to add an `if` condition around either\n        a window, group, popup, combobox or contextual menu `begin` and `end` block.\n        Example:\n            if (nk_begin(...) {...} nk_end(...); or\n            if (nk_group_begin(...) { nk_group_end(...);} */\n    NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));\n    NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));\n    NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));\n\n    /* need to convert to int here to remove floating point errors */\n    bounds->x = (float)((int)bounds->x);\n    bounds->y = (float)((int)bounds->y);\n    bounds->w = (float)((int)bounds->w);\n    bounds->h = (float)((int)bounds->h);\n\n    c.x = (float)((int)c.x);\n    c.y = (float)((int)c.y);\n    c.w = (float)((int)c.w);\n    c.h = (float)((int)c.h);\n\n    nk_unify(&v, &c, bounds->x, bounds->y, bounds->x + bounds->w, bounds->y + bounds->h);\n    if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds->x, bounds->y, bounds->w, bounds->h))\n        return NK_WIDGET_INVALID;\n    if (win->widgets_disabled)\n        return NK_WIDGET_DISABLED;\n    if (!NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, v.x, v.y, v.w, v.h))\n        return NK_WIDGET_ROM;\n    return NK_WIDGET_VALID;\n}\nNK_API enum nk_widget_layout_states\nnk_widget_fitting(struct nk_rect *bounds, const struct nk_context *ctx,\n    struct nk_vec2 item_padding)\n{\n    /* update the bounds to stand without padding  */\n    enum nk_widget_layout_states state;\n    NK_UNUSED(item_padding);\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return NK_WIDGET_INVALID;\n\n    state = nk_widget(bounds, ctx);\n    return state;\n}\nNK_API void\nnk_spacing(struct nk_context *ctx, int cols)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    struct nk_rect none;\n    int i, index, rows;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    /* spacing over row boundaries */\n    win = ctx->current;\n    layout = win->layout;\n    index = (layout->row.index + cols) % layout->row.columns;\n    rows = (layout->row.index + cols) / layout->row.columns;\n    if (rows) {\n        for (i = 0; i < rows; ++i)\n            nk_panel_alloc_row(ctx, win);\n        cols = index;\n    }\n    /* non table layout need to allocate space */\n    if (layout->row.type != NK_LAYOUT_DYNAMIC_FIXED &&\n        layout->row.type != NK_LAYOUT_STATIC_FIXED) {\n        for (i = 0; i < cols; ++i)\n            nk_panel_alloc_space(&none, ctx);\n    } layout->row.index = index;\n}\nNK_API void\nnk_widget_disable_begin(struct nk_context* ctx)\n{\n    struct nk_window* win;\n    struct nk_style* style;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n\n    if (!ctx || !ctx->current)\n        return;\n\n    win = ctx->current;\n    style = &ctx->style;\n\n    win->widgets_disabled = nk_true;\n\n    style->button.color_factor_text = style->button.disabled_factor;\n    style->button.color_factor_background = style->button.disabled_factor;\n    style->chart.color_factor = style->chart.disabled_factor;\n    style->checkbox.color_factor = style->checkbox.disabled_factor;\n    style->combo.color_factor = style->combo.disabled_factor;\n    style->combo.button.color_factor_text = style->combo.button.disabled_factor;\n    style->combo.button.color_factor_background = style->combo.button.disabled_factor;\n    style->contextual_button.color_factor_text = style->contextual_button.disabled_factor;\n    style->contextual_button.color_factor_background = style->contextual_button.disabled_factor;\n    style->edit.color_factor = style->edit.disabled_factor;\n    style->edit.scrollbar.color_factor = style->edit.scrollbar.disabled_factor;\n    style->menu_button.color_factor_text = style->menu_button.disabled_factor;\n    style->menu_button.color_factor_background = style->menu_button.disabled_factor;\n    style->option.color_factor = style->option.disabled_factor;\n    style->progress.color_factor = style->progress.disabled_factor;\n    style->property.color_factor = style->property.disabled_factor;\n    style->property.inc_button.color_factor_text = style->property.inc_button.disabled_factor;\n    style->property.inc_button.color_factor_background = style->property.inc_button.disabled_factor;\n    style->property.dec_button.color_factor_text = style->property.dec_button.disabled_factor;\n    style->property.dec_button.color_factor_background = style->property.dec_button.disabled_factor;\n    style->property.edit.color_factor = style->property.edit.disabled_factor;\n    style->scrollh.color_factor = style->scrollh.disabled_factor;\n    style->scrollh.inc_button.color_factor_text = style->scrollh.inc_button.disabled_factor;\n    style->scrollh.inc_button.color_factor_background = style->scrollh.inc_button.disabled_factor;\n    style->scrollh.dec_button.color_factor_text = style->scrollh.dec_button.disabled_factor;\n    style->scrollh.dec_button.color_factor_background = style->scrollh.dec_button.disabled_factor;\n    style->scrollv.color_factor = style->scrollv.disabled_factor;\n    style->scrollv.inc_button.color_factor_text = style->scrollv.inc_button.disabled_factor;\n    style->scrollv.inc_button.color_factor_background = style->scrollv.inc_button.disabled_factor;\n    style->scrollv.dec_button.color_factor_text = style->scrollv.dec_button.disabled_factor;\n    style->scrollv.dec_button.color_factor_background = style->scrollv.dec_button.disabled_factor;\n    style->selectable.color_factor = style->selectable.disabled_factor;\n    style->slider.color_factor = style->slider.disabled_factor;\n    style->slider.inc_button.color_factor_text = style->slider.inc_button.disabled_factor;\n    style->slider.inc_button.color_factor_background = style->slider.inc_button.disabled_factor;\n    style->slider.dec_button.color_factor_text = style->slider.dec_button.disabled_factor;\n    style->slider.dec_button.color_factor_background = style->slider.dec_button.disabled_factor;\n    style->tab.color_factor = style->tab.disabled_factor;\n    style->tab.node_maximize_button.color_factor_text = style->tab.node_maximize_button.disabled_factor;\n    style->tab.node_minimize_button.color_factor_text = style->tab.node_minimize_button.disabled_factor;\n    style->tab.tab_maximize_button.color_factor_text = style->tab.tab_maximize_button.disabled_factor;\n    style->tab.tab_maximize_button.color_factor_background = style->tab.tab_maximize_button.disabled_factor;\n    style->tab.tab_minimize_button.color_factor_text = style->tab.tab_minimize_button.disabled_factor;\n    style->tab.tab_minimize_button.color_factor_background = style->tab.tab_minimize_button.disabled_factor;\n    style->text.color_factor = style->text.disabled_factor;\n}\nNK_API void\nnk_widget_disable_end(struct nk_context* ctx)\n{\n    struct nk_window* win;\n    struct nk_style* style;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n\n    if (!ctx || !ctx->current)\n        return;\n\n    win = ctx->current;\n    style = &ctx->style;\n\n    win->widgets_disabled = nk_false;\n\n    style->button.color_factor_text = 1.0f;\n    style->button.color_factor_background = 1.0f;\n    style->chart.color_factor = 1.0f;\n    style->checkbox.color_factor = 1.0f;\n    style->combo.color_factor = 1.0f;\n    style->combo.button.color_factor_text = 1.0f;\n    style->combo.button.color_factor_background = 1.0f;\n    style->contextual_button.color_factor_text = 1.0f;\n    style->contextual_button.color_factor_background = 1.0f;\n    style->edit.color_factor = 1.0f;\n    style->edit.scrollbar.color_factor = 1.0f;\n    style->menu_button.color_factor_text = 1.0f;\n    style->menu_button.color_factor_background = 1.0f;\n    style->option.color_factor = 1.0f;\n    style->progress.color_factor = 1.0f;\n    style->property.color_factor = 1.0f;\n    style->property.inc_button.color_factor_text = 1.0f;\n    style->property.inc_button.color_factor_background = 1.0f;\n    style->property.dec_button.color_factor_text = 1.0f;\n    style->property.dec_button.color_factor_background = 1.0f;\n    style->property.edit.color_factor = 1.0f;\n    style->scrollh.color_factor = 1.0f;\n    style->scrollh.inc_button.color_factor_text = 1.0f;\n    style->scrollh.inc_button.color_factor_background = 1.0f;\n    style->scrollh.dec_button.color_factor_text = 1.0f;\n    style->scrollh.dec_button.color_factor_background = 1.0f;\n    style->scrollv.color_factor = 1.0f;\n    style->scrollv.inc_button.color_factor_text = 1.0f;\n    style->scrollv.inc_button.color_factor_background = 1.0f;\n    style->scrollv.dec_button.color_factor_text = 1.0f;\n    style->scrollv.dec_button.color_factor_background = 1.0f;\n    style->selectable.color_factor = 1.0f;\n    style->slider.color_factor = 1.0f;\n    style->slider.inc_button.color_factor_text = 1.0f;\n    style->slider.inc_button.color_factor_background = 1.0f;\n    style->slider.dec_button.color_factor_text = 1.0f;\n    style->slider.dec_button.color_factor_background = 1.0f;\n    style->tab.color_factor = 1.0f;\n    style->tab.node_maximize_button.color_factor_text = 1.0f;\n    style->tab.node_minimize_button.color_factor_text = 1.0f;\n    style->tab.tab_maximize_button.color_factor_text = 1.0f;\n    style->tab.tab_maximize_button.color_factor_background = 1.0f;\n    style->tab.tab_minimize_button.color_factor_text = 1.0f;\n    style->tab.tab_minimize_button.color_factor_background = 1.0f;\n    style->text.color_factor = 1.0f;\n}\n\n\n\n\n/* ===============================================================\n *\n *                              TEXT\n *\n * ===============================================================*/\nNK_LIB void\nnk_widget_text(struct nk_command_buffer *o, struct nk_rect b,\n    const char *string, int len, const struct nk_text *t,\n    nk_flags a, const struct nk_user_font *f)\n{\n    struct nk_rect label;\n    float text_width;\n\n    NK_ASSERT(o);\n    NK_ASSERT(t);\n    if (!o || !t) return;\n\n    b.h = NK_MAX(b.h, 2 * t->padding.y);\n\n    text_width = f->width(f->userdata, f->height, (const char*)string, len);\n    text_width += (2.0f * t->padding.x);\n\n    /* use top-left alignment by default */\n    if (!(a & (NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_CENTERED | NK_TEXT_ALIGN_RIGHT)))\n        a |= NK_TEXT_ALIGN_LEFT;\n    if (!(a & (NK_TEXT_ALIGN_TOP | NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_BOTTOM)))\n        a |= NK_TEXT_ALIGN_TOP;\n\n    /* align in x-axis */\n    if (a & NK_TEXT_ALIGN_LEFT) {\n        label.x = b.x + t->padding.x;\n        label.w = NK_MAX(0, b.w - 2 * t->padding.x);\n    } else if (a & NK_TEXT_ALIGN_CENTERED) {\n        label.w = NK_MAX(1, 2 * t->padding.x + (float)text_width);\n        label.x = (b.x + t->padding.x + ((b.w - 2 * t->padding.x) - label.w) / 2);\n        label.x = NK_MAX(b.x + t->padding.x, label.x);\n        label.w = NK_MIN(b.x + b.w, label.x + label.w);\n        if (label.w >= label.x) label.w -= label.x;\n    } else if (a & NK_TEXT_ALIGN_RIGHT) {\n        label.x = NK_MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (float)text_width));\n        label.w = (float)text_width + 2 * t->padding.x;\n    }\n\n    /* align in y-axis */\n    if (a & NK_TEXT_ALIGN_TOP) {\n        label.y = b.y + t->padding.y;\n        label.h = NK_MIN(f->height, b.h - 2 * t->padding.y);\n    } else if (a & NK_TEXT_ALIGN_MIDDLE) {\n        label.y = b.y + b.h/2.0f - (float)f->height/2.0f;\n        label.h = NK_MAX(b.h/2.0f, b.h - (b.h/2.0f + f->height/2.0f));\n    } else if (a & NK_TEXT_ALIGN_BOTTOM) {\n        label.y = b.y + b.h - f->height;\n        label.h = f->height;\n    }\n\n    nk_draw_text(o, label, (const char*)string, len, f, t->background, t->text);\n}\nNK_LIB void\nnk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b,\n    const char *string, int len, const struct nk_text *t,\n    const struct nk_user_font *f)\n{\n    float width;\n    int glyphs = 0;\n    int fitting = 0;\n    int done = 0;\n    struct nk_rect line;\n    struct nk_text text;\n    NK_INTERN nk_rune seperator[] = {' '};\n\n    NK_ASSERT(o);\n    NK_ASSERT(t);\n    if (!o || !t) return;\n\n    text.padding = nk_vec2(0,0);\n    text.background = t->background;\n    text.text = t->text;\n\n    b.w = NK_MAX(b.w, 2 * t->padding.x);\n    b.h = NK_MAX(b.h, 2 * t->padding.y);\n    b.h = b.h - 2 * t->padding.y;\n\n    line.x = b.x + t->padding.x;\n    line.y = b.y + t->padding.y;\n    line.w = b.w - 2 * t->padding.x;\n    line.h = 2 * t->padding.y + f->height;\n\n    fitting = nk_text_clamp(f, string, len, line.w, &glyphs, &width, seperator,NK_LEN(seperator));\n    while (done < len) {\n        if (!fitting || line.y + line.h >= (b.y + b.h)) break;\n        nk_widget_text(o, line, &string[done], fitting, &text, NK_TEXT_LEFT, f);\n        done += fitting;\n        line.y += f->height + 2 * t->padding.y;\n        fitting = nk_text_clamp(f, &string[done], len - done, line.w, &glyphs, &width, seperator,NK_LEN(seperator));\n    }\n}\nNK_API void\nnk_text_colored(struct nk_context *ctx, const char *str, int len,\n    nk_flags alignment, struct nk_color color)\n{\n    struct nk_window *win;\n    const struct nk_style *style;\n\n    struct nk_vec2 item_padding;\n    struct nk_rect bounds;\n    struct nk_text text;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) return;\n\n    win = ctx->current;\n    style = &ctx->style;\n    nk_panel_alloc_space(&bounds, ctx);\n    item_padding = style->text.padding;\n\n    text.padding.x = item_padding.x;\n    text.padding.y = item_padding.y;\n    text.background = style->window.background;\n    text.text = nk_rgb_factor(color, style->text.color_factor);\n    nk_widget_text(&win->buffer, bounds, str, len, &text, alignment, style->font);\n}\nNK_API void\nnk_text_wrap_colored(struct nk_context *ctx, const char *str,\n    int len, struct nk_color color)\n{\n    struct nk_window *win;\n    const struct nk_style *style;\n\n    struct nk_vec2 item_padding;\n    struct nk_rect bounds;\n    struct nk_text text;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) return;\n\n    win = ctx->current;\n    style = &ctx->style;\n    nk_panel_alloc_space(&bounds, ctx);\n    item_padding = style->text.padding;\n\n    text.padding.x = item_padding.x;\n    text.padding.y = item_padding.y;\n    text.background = style->window.background;\n    text.text = nk_rgb_factor(color, style->text.color_factor);\n    nk_widget_text_wrap(&win->buffer, bounds, str, len, &text, style->font);\n}\n#ifdef NK_INCLUDE_STANDARD_VARARGS\nNK_API void\nnk_labelf_colored(struct nk_context *ctx, nk_flags flags,\n    struct nk_color color, const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    nk_labelfv_colored(ctx, flags, color, fmt, args);\n    va_end(args);\n}\nNK_API void\nnk_labelf_colored_wrap(struct nk_context *ctx, struct nk_color color,\n    const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    nk_labelfv_colored_wrap(ctx, color, fmt, args);\n    va_end(args);\n}\nNK_API void\nnk_labelf(struct nk_context *ctx, nk_flags flags, const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    nk_labelfv(ctx, flags, fmt, args);\n    va_end(args);\n}\nNK_API void\nnk_labelf_wrap(struct nk_context *ctx, const char *fmt,...)\n{\n    va_list args;\n    va_start(args, fmt);\n    nk_labelfv_wrap(ctx, fmt, args);\n    va_end(args);\n}\nNK_API void\nnk_labelfv_colored(struct nk_context *ctx, nk_flags flags,\n    struct nk_color color, const char *fmt, va_list args)\n{\n    char buf[256];\n    nk_strfmt(buf, NK_LEN(buf), fmt, args);\n    nk_label_colored(ctx, buf, flags, color);\n}\n\nNK_API void\nnk_labelfv_colored_wrap(struct nk_context *ctx, struct nk_color color,\n    const char *fmt, va_list args)\n{\n    char buf[256];\n    nk_strfmt(buf, NK_LEN(buf), fmt, args);\n    nk_label_colored_wrap(ctx, buf, color);\n}\n\nNK_API void\nnk_labelfv(struct nk_context *ctx, nk_flags flags, const char *fmt, va_list args)\n{\n    char buf[256];\n    nk_strfmt(buf, NK_LEN(buf), fmt, args);\n    nk_label(ctx, buf, flags);\n}\n\nNK_API void\nnk_labelfv_wrap(struct nk_context *ctx, const char *fmt, va_list args)\n{\n    char buf[256];\n    nk_strfmt(buf, NK_LEN(buf), fmt, args);\n    nk_label_wrap(ctx, buf);\n}\n\nNK_API void\nnk_value_bool(struct nk_context *ctx, const char *prefix, int value)\n{\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: %s\", prefix, ((value) ? \"true\": \"false\"));\n}\nNK_API void\nnk_value_int(struct nk_context *ctx, const char *prefix, int value)\n{\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: %d\", prefix, value);\n}\nNK_API void\nnk_value_uint(struct nk_context *ctx, const char *prefix, unsigned int value)\n{\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: %u\", prefix, value);\n}\nNK_API void\nnk_value_float(struct nk_context *ctx, const char *prefix, float value)\n{\n    double double_value = (double)value;\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: %.3f\", prefix, double_value);\n}\nNK_API void\nnk_value_color_byte(struct nk_context *ctx, const char *p, struct nk_color c)\n{\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: (%d, %d, %d, %d)\", p, c.r, c.g, c.b, c.a);\n}\nNK_API void\nnk_value_color_float(struct nk_context *ctx, const char *p, struct nk_color color)\n{\n    double c[4]; nk_color_dv(c, color);\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: (%.2f, %.2f, %.2f, %.2f)\",\n        p, c[0], c[1], c[2], c[3]);\n}\nNK_API void\nnk_value_color_hex(struct nk_context *ctx, const char *prefix, struct nk_color color)\n{\n    char hex[16];\n    nk_color_hex_rgba(hex, color);\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: %s\", prefix, hex);\n}\n#endif\nNK_API void\nnk_text(struct nk_context *ctx, const char *str, int len, nk_flags alignment)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    nk_text_colored(ctx, str, len, alignment, ctx->style.text.color);\n}\nNK_API void\nnk_text_wrap(struct nk_context *ctx, const char *str, int len)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    nk_text_wrap_colored(ctx, str, len, ctx->style.text.color);\n}\nNK_API void\nnk_label(struct nk_context *ctx, const char *str, nk_flags alignment)\n{\n    nk_text(ctx, str, nk_strlen(str), alignment);\n}\nNK_API void\nnk_label_colored(struct nk_context *ctx, const char *str, nk_flags align,\n    struct nk_color color)\n{\n    nk_text_colored(ctx, str, nk_strlen(str), align, color);\n}\nNK_API void\nnk_label_wrap(struct nk_context *ctx, const char *str)\n{\n    nk_text_wrap(ctx, str, nk_strlen(str));\n}\nNK_API void\nnk_label_colored_wrap(struct nk_context *ctx, const char *str, struct nk_color color)\n{\n    nk_text_wrap_colored(ctx, str, nk_strlen(str), color);\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                          IMAGE\n *\n * ===============================================================*/\nNK_API nk_handle\nnk_handle_ptr(void *ptr)\n{\n    nk_handle handle = {0};\n    handle.ptr = ptr;\n    return handle;\n}\nNK_API nk_handle\nnk_handle_id(int id)\n{\n    nk_handle handle;\n    nk_zero_struct(handle);\n    handle.id = id;\n    return handle;\n}\nNK_API struct nk_image\nnk_subimage_ptr(void *ptr, nk_ushort w, nk_ushort h, struct nk_rect r)\n{\n    struct nk_image s;\n    nk_zero(&s, sizeof(s));\n    s.handle.ptr = ptr;\n    s.w = w; s.h = h;\n    s.region[0] = (nk_ushort)r.x;\n    s.region[1] = (nk_ushort)r.y;\n    s.region[2] = (nk_ushort)r.w;\n    s.region[3] = (nk_ushort)r.h;\n    return s;\n}\nNK_API struct nk_image\nnk_subimage_id(int id, nk_ushort w, nk_ushort h, struct nk_rect r)\n{\n    struct nk_image s;\n    nk_zero(&s, sizeof(s));\n    s.handle.id = id;\n    s.w = w; s.h = h;\n    s.region[0] = (nk_ushort)r.x;\n    s.region[1] = (nk_ushort)r.y;\n    s.region[2] = (nk_ushort)r.w;\n    s.region[3] = (nk_ushort)r.h;\n    return s;\n}\nNK_API struct nk_image\nnk_subimage_handle(nk_handle handle, nk_ushort w, nk_ushort h, struct nk_rect r)\n{\n    struct nk_image s;\n    nk_zero(&s, sizeof(s));\n    s.handle = handle;\n    s.w = w; s.h = h;\n    s.region[0] = (nk_ushort)r.x;\n    s.region[1] = (nk_ushort)r.y;\n    s.region[2] = (nk_ushort)r.w;\n    s.region[3] = (nk_ushort)r.h;\n    return s;\n}\nNK_API struct nk_image\nnk_image_handle(nk_handle handle)\n{\n    struct nk_image s;\n    nk_zero(&s, sizeof(s));\n    s.handle = handle;\n    s.w = 0; s.h = 0;\n    s.region[0] = 0;\n    s.region[1] = 0;\n    s.region[2] = 0;\n    s.region[3] = 0;\n    return s;\n}\nNK_API struct nk_image\nnk_image_ptr(void *ptr)\n{\n    struct nk_image s;\n    nk_zero(&s, sizeof(s));\n    NK_ASSERT(ptr);\n    s.handle.ptr = ptr;\n    s.w = 0; s.h = 0;\n    s.region[0] = 0;\n    s.region[1] = 0;\n    s.region[2] = 0;\n    s.region[3] = 0;\n    return s;\n}\nNK_API struct nk_image\nnk_image_id(int id)\n{\n    struct nk_image s;\n    nk_zero(&s, sizeof(s));\n    s.handle.id = id;\n    s.w = 0; s.h = 0;\n    s.region[0] = 0;\n    s.region[1] = 0;\n    s.region[2] = 0;\n    s.region[3] = 0;\n    return s;\n}\nNK_API nk_bool\nnk_image_is_subimage(const struct nk_image* img)\n{\n    NK_ASSERT(img);\n    return !(img->w == 0 && img->h == 0);\n}\nNK_API void\nnk_image(struct nk_context *ctx, struct nk_image img)\n{\n    struct nk_window *win;\n    struct nk_rect bounds;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) return;\n\n    win = ctx->current;\n    if (!nk_widget(&bounds, ctx)) return;\n    nk_draw_image(&win->buffer, bounds, &img, nk_white);\n}\nNK_API void\nnk_image_color(struct nk_context *ctx, struct nk_image img, struct nk_color col)\n{\n    struct nk_window *win;\n    struct nk_rect bounds;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) return;\n\n    win = ctx->current;\n    if (!nk_widget(&bounds, ctx)) return;\n    nk_draw_image(&win->buffer, bounds, &img, col);\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                          9-SLICE\n *\n * ===============================================================*/\nNK_API struct nk_nine_slice\nnk_sub9slice_ptr(void *ptr, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)\n{\n    struct nk_nine_slice s;\n    struct nk_image *i = &s.img;\n    nk_zero(&s, sizeof(s));\n    i->handle.ptr = ptr;\n    i->w = w; i->h = h;\n    i->region[0] = (nk_ushort)rgn.x;\n    i->region[1] = (nk_ushort)rgn.y;\n    i->region[2] = (nk_ushort)rgn.w;\n    i->region[3] = (nk_ushort)rgn.h;\n    s.l = l; s.t = t; s.r = r; s.b = b;\n    return s;\n}\nNK_API struct nk_nine_slice\nnk_sub9slice_id(int id, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)\n{\n    struct nk_nine_slice s;\n    struct nk_image *i = &s.img;\n    nk_zero(&s, sizeof(s));\n    i->handle.id = id;\n    i->w = w; i->h = h;\n    i->region[0] = (nk_ushort)rgn.x;\n    i->region[1] = (nk_ushort)rgn.y;\n    i->region[2] = (nk_ushort)rgn.w;\n    i->region[3] = (nk_ushort)rgn.h;\n    s.l = l; s.t = t; s.r = r; s.b = b;\n    return s;\n}\nNK_API struct nk_nine_slice\nnk_sub9slice_handle(nk_handle handle, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)\n{\n    struct nk_nine_slice s;\n    struct nk_image *i = &s.img;\n    nk_zero(&s, sizeof(s));\n    i->handle = handle;\n    i->w = w; i->h = h;\n    i->region[0] = (nk_ushort)rgn.x;\n    i->region[1] = (nk_ushort)rgn.y;\n    i->region[2] = (nk_ushort)rgn.w;\n    i->region[3] = (nk_ushort)rgn.h;\n    s.l = l; s.t = t; s.r = r; s.b = b;\n    return s;\n}\nNK_API struct nk_nine_slice\nnk_nine_slice_handle(nk_handle handle, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)\n{\n    struct nk_nine_slice s;\n    struct nk_image *i = &s.img;\n    nk_zero(&s, sizeof(s));\n    i->handle = handle;\n    i->w = 0; i->h = 0;\n    i->region[0] = 0;\n    i->region[1] = 0;\n    i->region[2] = 0;\n    i->region[3] = 0;\n    s.l = l; s.t = t; s.r = r; s.b = b;\n    return s;\n}\nNK_API struct nk_nine_slice\nnk_nine_slice_ptr(void *ptr, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)\n{\n    struct nk_nine_slice s;\n    struct nk_image *i = &s.img;\n    nk_zero(&s, sizeof(s));\n    NK_ASSERT(ptr);\n    i->handle.ptr = ptr;\n    i->w = 0; i->h = 0;\n    i->region[0] = 0;\n    i->region[1] = 0;\n    i->region[2] = 0;\n    i->region[3] = 0;\n    s.l = l; s.t = t; s.r = r; s.b = b;\n    return s;\n}\nNK_API struct nk_nine_slice\nnk_nine_slice_id(int id, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)\n{\n    struct nk_nine_slice s;\n    struct nk_image *i = &s.img;\n    nk_zero(&s, sizeof(s));\n    i->handle.id = id;\n    i->w = 0; i->h = 0;\n    i->region[0] = 0;\n    i->region[1] = 0;\n    i->region[2] = 0;\n    i->region[3] = 0;\n    s.l = l; s.t = t; s.r = r; s.b = b;\n    return s;\n}\nNK_API int\nnk_nine_slice_is_sub9slice(const struct nk_nine_slice* slice)\n{\n    NK_ASSERT(slice);\n    return !(slice->img.w == 0 && slice->img.h == 0);\n}\n\n\n\n\n\n/* ==============================================================\n *\n *                          BUTTON\n *\n * ===============================================================*/\nNK_LIB void\nnk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type,\n    struct nk_rect content, struct nk_color background, struct nk_color foreground,\n    float border_width, const struct nk_user_font *font)\n{\n    switch (type) {\n    case NK_SYMBOL_X:\n    case NK_SYMBOL_UNDERSCORE:\n    case NK_SYMBOL_PLUS:\n    case NK_SYMBOL_MINUS: {\n        /* single character text symbol */\n        const char *X = (type == NK_SYMBOL_X) ? \"x\":\n            (type == NK_SYMBOL_UNDERSCORE) ? \"_\":\n            (type == NK_SYMBOL_PLUS) ? \"+\": \"-\";\n        struct nk_text text;\n        text.padding = nk_vec2(0,0);\n        text.background = background;\n        text.text = foreground;\n        nk_widget_text(out, content, X, 1, &text, NK_TEXT_CENTERED, font);\n    } break;\n    case NK_SYMBOL_CIRCLE_SOLID:\n    case NK_SYMBOL_CIRCLE_OUTLINE:\n    case NK_SYMBOL_RECT_SOLID:\n    case NK_SYMBOL_RECT_OUTLINE: {\n        /* simple empty/filled shapes */\n        if (type == NK_SYMBOL_RECT_SOLID || type == NK_SYMBOL_RECT_OUTLINE) {\n            nk_fill_rect(out, content,  0, foreground);\n            if (type == NK_SYMBOL_RECT_OUTLINE)\n                nk_fill_rect(out, nk_shrink_rect(content, border_width), 0, background);\n        } else {\n            nk_fill_circle(out, content, foreground);\n            if (type == NK_SYMBOL_CIRCLE_OUTLINE)\n                nk_fill_circle(out, nk_shrink_rect(content, 1), background);\n        }\n    } break;\n    case NK_SYMBOL_TRIANGLE_UP:\n    case NK_SYMBOL_TRIANGLE_DOWN:\n    case NK_SYMBOL_TRIANGLE_LEFT:\n    case NK_SYMBOL_TRIANGLE_RIGHT: {\n        enum nk_heading heading;\n        struct nk_vec2 points[3];\n        heading = (type == NK_SYMBOL_TRIANGLE_RIGHT) ? NK_RIGHT :\n            (type == NK_SYMBOL_TRIANGLE_LEFT) ? NK_LEFT:\n            (type == NK_SYMBOL_TRIANGLE_UP) ? NK_UP: NK_DOWN;\n        nk_triangle_from_direction(points, content, 0, 0, heading);\n        nk_fill_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y,\n            points[2].x, points[2].y, foreground);\n    } break;\n    case NK_SYMBOL_TRIANGLE_UP_OUTLINE:\n    case NK_SYMBOL_TRIANGLE_DOWN_OUTLINE:\n    case NK_SYMBOL_TRIANGLE_LEFT_OUTLINE:\n    case NK_SYMBOL_TRIANGLE_RIGHT_OUTLINE: {\n        enum nk_heading heading;\n        struct nk_vec2 points[3];\n        heading = (type == NK_SYMBOL_TRIANGLE_RIGHT_OUTLINE) ? NK_RIGHT :\n            (type == NK_SYMBOL_TRIANGLE_LEFT_OUTLINE) ? NK_LEFT:\n            (type == NK_SYMBOL_TRIANGLE_UP_OUTLINE) ? NK_UP: NK_DOWN;\n        nk_triangle_from_direction(points, content, 0, 0, heading);\n        nk_stroke_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y,\n            points[2].x, points[2].y, border_width, foreground);\n    } break;\n    default:\n    case NK_SYMBOL_NONE:\n    case NK_SYMBOL_MAX: break;\n    }\n}\nNK_LIB nk_bool\nnk_button_behavior(nk_flags *state, struct nk_rect r,\n    const struct nk_input *i, enum nk_button_behavior behavior)\n{\n    int ret = 0;\n    nk_widget_state_reset(state);\n    if (!i) return 0;\n    if (nk_input_is_mouse_hovering_rect(i, r)) {\n        *state = NK_WIDGET_STATE_HOVERED;\n        if (nk_input_is_mouse_down(i, NK_BUTTON_LEFT))\n            *state = NK_WIDGET_STATE_ACTIVE;\n        if (nk_input_has_mouse_click_in_button_rect(i, NK_BUTTON_LEFT, r)) {\n            ret = (behavior != NK_BUTTON_DEFAULT) ?\n                nk_input_is_mouse_down(i, NK_BUTTON_LEFT):\n#ifdef NK_BUTTON_TRIGGER_ON_RELEASE\n                nk_input_is_mouse_released(i, NK_BUTTON_LEFT);\n#else\n                nk_input_is_mouse_pressed(i, NK_BUTTON_LEFT);\n#endif\n        }\n    }\n    if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(i, r))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(i, r))\n        *state |= NK_WIDGET_STATE_LEFT;\n    return ret;\n}\nNK_LIB const struct nk_style_item*\nnk_draw_button(struct nk_command_buffer *out,\n    const struct nk_rect *bounds, nk_flags state,\n    const struct nk_style_button *style)\n{\n    const struct nk_style_item *background;\n    if (state & NK_WIDGET_STATE_HOVER)\n        background = &style->hover;\n    else if (state & NK_WIDGET_STATE_ACTIVED)\n        background = &style->active;\n    else background = &style->normal;\n\n    switch (background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor_background));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor_background));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor_background));\n            nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor_background));\n            break;\n    }\n    return background;\n}\nNK_LIB nk_bool\nnk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r,\n    const struct nk_style_button *style, const struct nk_input *in,\n    enum nk_button_behavior behavior, struct nk_rect *content)\n{\n    struct nk_rect bounds;\n    NK_ASSERT(style);\n    NK_ASSERT(state);\n    NK_ASSERT(out);\n    if (!out || !style)\n        return nk_false;\n\n    /* calculate button content space */\n    content->x = r.x + style->padding.x + style->border + style->rounding;\n    content->y = r.y + style->padding.y + style->border + style->rounding;\n    content->w = r.w - (2 * (style->padding.x + style->border + style->rounding));\n    content->h = r.h - (2 * (style->padding.y + style->border + style->rounding));\n\n    /* execute button behavior */\n    bounds.x = r.x - style->touch_padding.x;\n    bounds.y = r.y - style->touch_padding.y;\n    bounds.w = r.w + 2 * style->touch_padding.x;\n    bounds.h = r.h + 2 * style->touch_padding.y;\n    return nk_button_behavior(state, bounds, in, behavior);\n}\nNK_LIB void\nnk_draw_button_text(struct nk_command_buffer *out,\n    const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state,\n    const struct nk_style_button *style, const char *txt, int len,\n    nk_flags text_alignment, const struct nk_user_font *font)\n{\n    struct nk_text text;\n    const struct nk_style_item *background;\n    background = nk_draw_button(out, bounds, state, style);\n\n    /* select correct colors/images */\n    if (background->type == NK_STYLE_ITEM_COLOR)\n        text.background = background->data.color;\n    else text.background = style->text_background;\n    if (state & NK_WIDGET_STATE_HOVER)\n        text.text = style->text_hover;\n    else if (state & NK_WIDGET_STATE_ACTIVED)\n        text.text = style->text_active;\n    else text.text = style->text_normal;\n\n    text.text = nk_rgb_factor(text.text, style->color_factor_text);\n\n    text.padding = nk_vec2(0,0);\n    nk_widget_text(out, *content, txt, len, &text, text_alignment, font);\n}\nNK_LIB nk_bool\nnk_do_button_text(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    const char *string, int len, nk_flags align, enum nk_button_behavior behavior,\n    const struct nk_style_button *style, const struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    struct nk_rect content;\n    int ret = nk_false;\n\n    NK_ASSERT(state);\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    NK_ASSERT(string);\n    NK_ASSERT(font);\n    if (!out || !style || !font || !string)\n        return nk_false;\n\n    ret = nk_do_button(state, out, bounds, style, in, behavior, &content);\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_button_text(out, &bounds, &content, *state, style, string, len, align, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return ret;\n}\nNK_LIB void\nnk_draw_button_symbol(struct nk_command_buffer *out,\n    const struct nk_rect *bounds, const struct nk_rect *content,\n    nk_flags state, const struct nk_style_button *style,\n    enum nk_symbol_type type, const struct nk_user_font *font)\n{\n    struct nk_color sym, bg;\n    const struct nk_style_item *background;\n\n    /* select correct colors/images */\n    background = nk_draw_button(out, bounds, state, style);\n    if (background->type == NK_STYLE_ITEM_COLOR)\n        bg = background->data.color;\n    else bg = style->text_background;\n\n    if (state & NK_WIDGET_STATE_HOVER)\n        sym = style->text_hover;\n    else if (state & NK_WIDGET_STATE_ACTIVED)\n        sym = style->text_active;\n    else sym = style->text_normal;\n\n    sym = nk_rgb_factor(sym, style->color_factor_text);\n    nk_draw_symbol(out, type, *content, bg, sym, 1, font);\n}\nNK_LIB nk_bool\nnk_do_button_symbol(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    enum nk_symbol_type symbol, enum nk_button_behavior behavior,\n    const struct nk_style_button *style, const struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    int ret;\n    struct nk_rect content;\n\n    NK_ASSERT(state);\n    NK_ASSERT(style);\n    NK_ASSERT(font);\n    NK_ASSERT(out);\n    if (!out || !style || !font || !state)\n        return nk_false;\n\n    ret = nk_do_button(state, out, bounds, style, in, behavior, &content);\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_button_symbol(out, &bounds, &content, *state, style, symbol, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return ret;\n}\nNK_LIB void\nnk_draw_button_image(struct nk_command_buffer *out,\n    const struct nk_rect *bounds, const struct nk_rect *content,\n    nk_flags state, const struct nk_style_button *style, const struct nk_image *img)\n{\n    nk_draw_button(out, bounds, state, style);\n    nk_draw_image(out, *content, img, nk_rgb_factor(nk_white, style->color_factor_background));\n}\nNK_LIB nk_bool\nnk_do_button_image(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    struct nk_image img, enum nk_button_behavior b,\n    const struct nk_style_button *style, const struct nk_input *in)\n{\n    int ret;\n    struct nk_rect content;\n\n    NK_ASSERT(state);\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    if (!out || !style || !state)\n        return nk_false;\n\n    ret = nk_do_button(state, out, bounds, style, in, b, &content);\n    content.x += style->image_padding.x;\n    content.y += style->image_padding.y;\n    content.w -= 2 * style->image_padding.x;\n    content.h -= 2 * style->image_padding.y;\n\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_button_image(out, &bounds, &content, *state, style, &img);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return ret;\n}\nNK_LIB void\nnk_draw_button_text_symbol(struct nk_command_buffer *out,\n    const struct nk_rect *bounds, const struct nk_rect *label,\n    const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style,\n    const char *str, int len, enum nk_symbol_type type,\n    const struct nk_user_font *font)\n{\n    struct nk_color sym;\n    struct nk_text text;\n    const struct nk_style_item *background;\n\n    /* select correct background colors/images */\n    background = nk_draw_button(out, bounds, state, style);\n    if (background->type == NK_STYLE_ITEM_COLOR)\n        text.background = background->data.color;\n    else text.background = style->text_background;\n\n    /* select correct text colors */\n    if (state & NK_WIDGET_STATE_HOVER) {\n        sym = style->text_hover;\n        text.text = style->text_hover;\n    } else if (state & NK_WIDGET_STATE_ACTIVED) {\n        sym = style->text_active;\n        text.text = style->text_active;\n    } else {\n        sym = style->text_normal;\n        text.text = style->text_normal;\n    }\n\n    sym = nk_rgb_factor(sym, style->color_factor_text);\n    text.text = nk_rgb_factor(text.text, style->color_factor_text);\n    text.padding = nk_vec2(0,0);\n    nk_draw_symbol(out, type, *symbol, style->text_background, sym, 0, font);\n    nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font);\n}\nNK_LIB nk_bool\nnk_do_button_text_symbol(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    enum nk_symbol_type symbol, const char *str, int len, nk_flags align,\n    enum nk_button_behavior behavior, const struct nk_style_button *style,\n    const struct nk_user_font *font, const struct nk_input *in)\n{\n    int ret;\n    struct nk_rect tri = {0,0,0,0};\n    struct nk_rect content;\n\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    NK_ASSERT(font);\n    if (!out || !style || !font)\n        return nk_false;\n\n    ret = nk_do_button(state, out, bounds, style, in, behavior, &content);\n    tri.y = content.y + (content.h/2) - font->height/2;\n    tri.w = font->height; tri.h = font->height;\n    if (align & NK_TEXT_ALIGN_LEFT) {\n        tri.x = (content.x + content.w) - (2 * style->padding.x + tri.w);\n        tri.x = NK_MAX(tri.x, 0);\n    } else tri.x = content.x + 2 * style->padding.x;\n\n    /* draw button */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_button_text_symbol(out, &bounds, &content, &tri,\n        *state, style, str, len, symbol, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return ret;\n}\nNK_LIB void\nnk_draw_button_text_image(struct nk_command_buffer *out,\n    const struct nk_rect *bounds, const struct nk_rect *label,\n    const struct nk_rect *image, nk_flags state, const struct nk_style_button *style,\n    const char *str, int len, const struct nk_user_font *font,\n    const struct nk_image *img)\n{\n    struct nk_text text;\n    const struct nk_style_item *background;\n    background = nk_draw_button(out, bounds, state, style);\n\n    /* select correct colors */\n    if (background->type == NK_STYLE_ITEM_COLOR)\n        text.background = background->data.color;\n    else text.background = style->text_background;\n    if (state & NK_WIDGET_STATE_HOVER)\n        text.text = style->text_hover;\n    else if (state & NK_WIDGET_STATE_ACTIVED)\n        text.text = style->text_active;\n    else text.text = style->text_normal;\n\n    text.text = nk_rgb_factor(text.text, style->color_factor_text);\n    text.padding = nk_vec2(0, 0);\n    nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font);\n    nk_draw_image(out, *image, img, nk_rgb_factor(nk_white, style->color_factor_background));\n}\nNK_LIB nk_bool\nnk_do_button_text_image(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    struct nk_image img, const char* str, int len, nk_flags align,\n    enum nk_button_behavior behavior, const struct nk_style_button *style,\n    const struct nk_user_font *font, const struct nk_input *in)\n{\n    int ret;\n    struct nk_rect icon;\n    struct nk_rect content;\n\n    NK_ASSERT(style);\n    NK_ASSERT(state);\n    NK_ASSERT(font);\n    NK_ASSERT(out);\n    if (!out || !font || !style || !str)\n        return nk_false;\n\n    ret = nk_do_button(state, out, bounds, style, in, behavior, &content);\n    icon.y = bounds.y + style->padding.y;\n    icon.w = icon.h = bounds.h - 2 * style->padding.y;\n    if (align & NK_TEXT_ALIGN_LEFT) {\n        icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);\n        icon.x = NK_MAX(icon.x, 0);\n    } else icon.x = bounds.x + 2 * style->padding.x;\n\n    icon.x += style->image_padding.x;\n    icon.y += style->image_padding.y;\n    icon.w -= 2 * style->image_padding.x;\n    icon.h -= 2 * style->image_padding.y;\n\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_button_text_image(out, &bounds, &content, &icon, *state, style, str, len, font, &img);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return ret;\n}\nNK_API void\nnk_button_set_behavior(struct nk_context *ctx, enum nk_button_behavior behavior)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    ctx->button_behavior = behavior;\n}\nNK_API nk_bool\nnk_button_push_behavior(struct nk_context *ctx, enum nk_button_behavior behavior)\n{\n    struct nk_config_stack_button_behavior *button_stack;\n    struct nk_config_stack_button_behavior_element *element;\n\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n\n    button_stack = &ctx->stacks.button_behaviors;\n    NK_ASSERT(button_stack->head < (int)NK_LEN(button_stack->elements));\n    if (button_stack->head >= (int)NK_LEN(button_stack->elements))\n        return 0;\n\n    element = &button_stack->elements[button_stack->head++];\n    element->address = &ctx->button_behavior;\n    element->old_value = ctx->button_behavior;\n    ctx->button_behavior = behavior;\n    return 1;\n}\nNK_API nk_bool\nnk_button_pop_behavior(struct nk_context *ctx)\n{\n    struct nk_config_stack_button_behavior *button_stack;\n    struct nk_config_stack_button_behavior_element *element;\n\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n\n    button_stack = &ctx->stacks.button_behaviors;\n    NK_ASSERT(button_stack->head > 0);\n    if (button_stack->head < 1)\n        return 0;\n\n    element = &button_stack->elements[--button_stack->head];\n    *element->address = element->old_value;\n    return 1;\n}\nNK_API nk_bool\nnk_button_text_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, const char *title, int len)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(style);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!style || !ctx || !ctx->current || !ctx->current->layout) return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n    state = nk_widget(&bounds, ctx);\n\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,\n                    title, len, style->text_alignment, ctx->button_behavior,\n                    style, in, ctx->style.font);\n}\nNK_API nk_bool\nnk_button_text(struct nk_context *ctx, const char *title, int len)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    return nk_button_text_styled(ctx, &ctx->style.button, title, len);\n}\nNK_API nk_bool nk_button_label_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, const char *title)\n{\n    return nk_button_text_styled(ctx, style, title, nk_strlen(title));\n}\nNK_API nk_bool nk_button_label(struct nk_context *ctx, const char *title)\n{\n    return nk_button_text(ctx, title, nk_strlen(title));\n}\nNK_API nk_bool\nnk_button_color(struct nk_context *ctx, struct nk_color color)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    struct nk_style_button button;\n\n    int ret = 0;\n    struct nk_rect bounds;\n    struct nk_rect content;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n\n    button = ctx->style.button;\n    button.normal = nk_style_item_color(color);\n    button.hover = nk_style_item_color(color);\n    button.active = nk_style_item_color(color);\n    ret = nk_do_button(&ctx->last_widget_state, &win->buffer, bounds,\n                &button, in, ctx->button_behavior, &content);\n    nk_draw_button(&win->buffer, &bounds, ctx->last_widget_state, &button);\n    return ret;\n}\nNK_API nk_bool\nnk_button_symbol_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, enum nk_symbol_type symbol)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, bounds,\n            symbol, ctx->button_behavior, style, in, ctx->style.font);\n}\nNK_API nk_bool\nnk_button_symbol(struct nk_context *ctx, enum nk_symbol_type symbol)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    return nk_button_symbol_styled(ctx, &ctx->style.button, symbol);\n}\nNK_API nk_bool\nnk_button_image_styled(struct nk_context *ctx, const struct nk_style_button *style,\n    struct nk_image img)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_button_image(&ctx->last_widget_state, &win->buffer, bounds,\n                img, ctx->button_behavior, style, in);\n}\nNK_API nk_bool\nnk_button_image(struct nk_context *ctx, struct nk_image img)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    return nk_button_image_styled(ctx, &ctx->style.button, img);\n}\nNK_API nk_bool\nnk_button_symbol_text_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, enum nk_symbol_type symbol,\n    const char *text, int len, nk_flags align)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,\n                symbol, text, len, align, ctx->button_behavior,\n                style, ctx->style.font, in);\n}\nNK_API nk_bool\nnk_button_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,\n    const char* text, int len, nk_flags align)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    return nk_button_symbol_text_styled(ctx, &ctx->style.button, symbol, text, len, align);\n}\nNK_API nk_bool nk_button_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,\n    const char *label, nk_flags align)\n{\n    return nk_button_symbol_text(ctx, symbol, label, nk_strlen(label), align);\n}\nNK_API nk_bool nk_button_symbol_label_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, enum nk_symbol_type symbol,\n    const char *title, nk_flags align)\n{\n    return nk_button_symbol_text_styled(ctx, style, symbol, title, nk_strlen(title), align);\n}\nNK_API nk_bool\nnk_button_image_text_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, struct nk_image img, const char *text,\n    int len, nk_flags align)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_button_text_image(&ctx->last_widget_state, &win->buffer,\n            bounds, img, text, len, align, ctx->button_behavior,\n            style, ctx->style.font, in);\n}\nNK_API nk_bool\nnk_button_image_text(struct nk_context *ctx, struct nk_image img,\n    const char *text, int len, nk_flags align)\n{\n    return nk_button_image_text_styled(ctx, &ctx->style.button,img, text, len, align);\n}\nNK_API nk_bool nk_button_image_label(struct nk_context *ctx, struct nk_image img,\n    const char *label, nk_flags align)\n{\n    return nk_button_image_text(ctx, img, label, nk_strlen(label), align);\n}\nNK_API nk_bool nk_button_image_label_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, struct nk_image img,\n    const char *label, nk_flags text_alignment)\n{\n    return nk_button_image_text_styled(ctx, style, img, label, nk_strlen(label), text_alignment);\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                              TOGGLE\n *\n * ===============================================================*/\nNK_LIB nk_bool\nnk_toggle_behavior(const struct nk_input *in, struct nk_rect select,\n    nk_flags *state, nk_bool active)\n{\n    nk_widget_state_reset(state);\n    if (nk_button_behavior(state, select, in, NK_BUTTON_DEFAULT)) {\n        *state = NK_WIDGET_STATE_ACTIVE;\n        active = !active;\n    }\n    if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, select))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, select))\n        *state |= NK_WIDGET_STATE_LEFT;\n    return active;\n}\nNK_LIB void\nnk_draw_checkbox(struct nk_command_buffer *out,\n    nk_flags state, const struct nk_style_toggle *style, nk_bool active,\n    const struct nk_rect *label, const struct nk_rect *selector,\n    const struct nk_rect *cursors, const char *string, int len,\n    const struct nk_user_font *font, nk_flags text_alignment)\n{\n    const struct nk_style_item *background;\n    const struct nk_style_item *cursor;\n    struct nk_text text;\n\n    /* select correct colors/images */\n    if (state & NK_WIDGET_STATE_HOVER) {\n        background = &style->hover;\n        cursor = &style->cursor_hover;\n        text.text = style->text_hover;\n    } else if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->hover;\n        cursor = &style->cursor_hover;\n        text.text = style->text_active;\n    } else {\n        background = &style->normal;\n        cursor = &style->cursor_normal;\n        text.text = style->text_normal;\n    }\n\n    text.text = nk_rgb_factor(text.text, style->color_factor);\n    text.padding.x = 0;\n    text.padding.y = 0;\n    text.background = style->text_background;\n    nk_widget_text(out, *label, string, len, &text, text_alignment, font);\n\n    /* draw background and cursor */\n    if (background->type == NK_STYLE_ITEM_COLOR) {\n        nk_fill_rect(out, *selector, 0, nk_rgb_factor(style->border_color, style->color_factor));\n        nk_fill_rect(out, nk_shrink_rect(*selector, style->border), 0, nk_rgb_factor(background->data.color, style->color_factor));\n    } else nk_draw_image(out, *selector, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n    if (active) {\n        if (cursor->type == NK_STYLE_ITEM_IMAGE)\n            nk_draw_image(out, *cursors, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));\n        else nk_fill_rect(out, *cursors, 0, cursor->data.color);\n    }\n}\nNK_LIB void\nnk_draw_option(struct nk_command_buffer *out,\n    nk_flags state, const struct nk_style_toggle *style, nk_bool active,\n    const struct nk_rect *label, const struct nk_rect *selector,\n    const struct nk_rect *cursors, const char *string, int len,\n    const struct nk_user_font *font, nk_flags text_alignment)\n{\n    const struct nk_style_item *background;\n    const struct nk_style_item *cursor;\n    struct nk_text text;\n\n    /* select correct colors/images */\n    if (state & NK_WIDGET_STATE_HOVER) {\n        background = &style->hover;\n        cursor = &style->cursor_hover;\n        text.text = style->text_hover;\n    } else if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->hover;\n        cursor = &style->cursor_hover;\n        text.text = style->text_active;\n    } else {\n        background = &style->normal;\n        cursor = &style->cursor_normal;\n        text.text = style->text_normal;\n    }\n\n    text.text = nk_rgb_factor(text.text, style->color_factor);\n    text.padding.x = 0;\n    text.padding.y = 0;\n    text.background = style->text_background;\n    nk_widget_text(out, *label, string, len, &text, text_alignment, font);\n\n    /* draw background and cursor */\n    if (background->type == NK_STYLE_ITEM_COLOR) {\n        nk_fill_circle(out, *selector, nk_rgb_factor(style->border_color, style->color_factor));\n        nk_fill_circle(out, nk_shrink_rect(*selector, style->border), nk_rgb_factor(background->data.color, style->color_factor));\n    } else nk_draw_image(out, *selector, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n    if (active) {\n        if (cursor->type == NK_STYLE_ITEM_IMAGE)\n            nk_draw_image(out, *cursors, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));\n        else nk_fill_circle(out, *cursors, cursor->data.color);\n    }\n}\nNK_LIB nk_bool\nnk_do_toggle(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect r,\n    nk_bool *active, const char *str, int len, enum nk_toggle_type type,\n    const struct nk_style_toggle *style, const struct nk_input *in,\n    const struct nk_user_font *font, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    int was_active;\n    struct nk_rect bounds;\n    struct nk_rect select;\n    struct nk_rect cursor;\n    struct nk_rect label;\n\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    NK_ASSERT(font);\n    if (!out || !style || !font || !active)\n        return 0;\n\n    r.w = NK_MAX(r.w, font->height + 2 * style->padding.x);\n    r.h = NK_MAX(r.h, font->height + 2 * style->padding.y);\n\n    /* add additional touch padding for touch screen devices */\n    bounds.x = r.x - style->touch_padding.x;\n    bounds.y = r.y - style->touch_padding.y;\n    bounds.w = r.w + 2 * style->touch_padding.x;\n    bounds.h = r.h + 2 * style->touch_padding.y;\n\n    /* calculate the selector space */\n    select.w = font->height;\n    select.h = select.w;\n\n    if (widget_alignment & NK_WIDGET_ALIGN_RIGHT) {\n        select.x = r.x + r.w - font->height;\n\n        /* label in front of the selector */\n        label.x = r.x;\n        label.w = r.w - select.w - style->spacing * 2;\n    } else if (widget_alignment & NK_WIDGET_ALIGN_CENTERED) {\n        select.x = r.x + (r.w - select.w) / 2;\n\n        /* label in front of selector */\n        label.x = r.x;\n        label.w = (r.w - select.w - style->spacing * 2) / 2;\n    } else { /* Default: NK_WIDGET_ALIGN_LEFT */\n        select.x = r.x;\n\n        /* label behind the selector */\n        label.x = select.x + select.w + style->spacing;\n        label.w = NK_MAX(r.x + r.w, label.x) - label.x;\n    }\n\n    if (widget_alignment & NK_WIDGET_ALIGN_TOP) {\n        select.y = r.y;\n    } else if (widget_alignment & NK_WIDGET_ALIGN_BOTTOM) {\n        select.y = r.y + r.h - select.h - 2 * style->padding.y;\n    } else { /* Default: NK_WIDGET_ALIGN_MIDDLE */\n        select.y = r.y + r.h/2.0f - select.h/2.0f;\n    }\n\n    label.y = select.y;\n    label.h = select.w;\n\n    /* calculate the bounds of the cursor inside the selector */\n    cursor.x = select.x + style->padding.x + style->border;\n    cursor.y = select.y + style->padding.y + style->border;\n    cursor.w = select.w - (2 * style->padding.x + 2 * style->border);\n    cursor.h = select.h - (2 * style->padding.y + 2 * style->border);\n\n    /* update selector */\n    was_active = *active;\n    *active = nk_toggle_behavior(in, bounds, state, *active);\n\n    /* draw selector */\n    if (style->draw_begin)\n        style->draw_begin(out, style->userdata);\n    if (type == NK_TOGGLE_CHECK) {\n        nk_draw_checkbox(out, *state, style, *active, &label, &select, &cursor, str, len, font, text_alignment);\n    } else {\n        nk_draw_option(out, *state, style, *active, &label, &select, &cursor, str, len, font, text_alignment);\n    }\n    if (style->draw_end)\n        style->draw_end(out, style->userdata);\n    return (was_active != *active);\n}\n/*----------------------------------------------------------------\n *\n *                          CHECKBOX\n *\n * --------------------------------------------------------------*/\nNK_API nk_bool\nnk_check_text(struct nk_context *ctx, const char *text, int len, nk_bool active)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return active;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return active;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active,\n        text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font, NK_WIDGET_LEFT, NK_TEXT_LEFT);\n    return active;\n}\nNK_API nk_bool\nnk_check_text_align(struct nk_context *ctx, const char *text, int len, nk_bool active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return active;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return active;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active,\n        text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font, widget_alignment, text_alignment);\n    return active;\n}\nNK_API unsigned int\nnk_check_flags_text(struct nk_context *ctx, const char *text, int len,\n    unsigned int flags, unsigned int value)\n{\n    int old_active;\n    NK_ASSERT(ctx);\n    NK_ASSERT(text);\n    if (!ctx || !text) return flags;\n    old_active = (int)((flags & value) & value);\n    if (nk_check_text(ctx, text, len, old_active))\n        flags |= value;\n    else flags &= ~value;\n    return flags;\n}\nNK_API nk_bool\nnk_checkbox_text(struct nk_context *ctx, const char *text, int len, nk_bool *active)\n{\n    int old_val;\n    NK_ASSERT(ctx);\n    NK_ASSERT(text);\n    NK_ASSERT(active);\n    if (!ctx || !text || !active) return 0;\n    old_val = *active;\n    *active = nk_check_text(ctx, text, len, *active);\n    return old_val != *active;\n}\nNK_API nk_bool\nnk_checkbox_text_align(struct nk_context *ctx, const char *text, int len, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    int old_val;\n    NK_ASSERT(ctx);\n    NK_ASSERT(text);\n    NK_ASSERT(active);\n    if (!ctx || !text || !active) return 0;\n    old_val = *active;\n    *active = nk_check_text_align(ctx, text, len, *active, widget_alignment, text_alignment);\n    return old_val != *active;\n}\nNK_API nk_bool\nnk_checkbox_flags_text(struct nk_context *ctx, const char *text, int len,\n    unsigned int *flags, unsigned int value)\n{\n    nk_bool active;\n    NK_ASSERT(ctx);\n    NK_ASSERT(text);\n    NK_ASSERT(flags);\n    if (!ctx || !text || !flags) return 0;\n\n    active = (int)((*flags & value) & value);\n    if (nk_checkbox_text(ctx, text, len, &active)) {\n        if (active) *flags |= value;\n        else *flags &= ~value;\n        return 1;\n    }\n    return 0;\n}\nNK_API nk_bool nk_check_label(struct nk_context *ctx, const char *label, nk_bool active)\n{\n    return nk_check_text(ctx, label, nk_strlen(label), active);\n}\nNK_API unsigned int nk_check_flags_label(struct nk_context *ctx, const char *label,\n    unsigned int flags, unsigned int value)\n{\n    return nk_check_flags_text(ctx, label, nk_strlen(label), flags, value);\n}\nNK_API nk_bool nk_checkbox_label(struct nk_context *ctx, const char *label, nk_bool *active)\n{\n    return nk_checkbox_text(ctx, label, nk_strlen(label), active);\n}\nNK_API nk_bool nk_checkbox_label_align(struct nk_context *ctx, const char *label, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    return nk_checkbox_text_align(ctx, label, nk_strlen(label), active, widget_alignment, text_alignment);\n}\nNK_API nk_bool nk_checkbox_flags_label(struct nk_context *ctx, const char *label,\n    unsigned int *flags, unsigned int value)\n{\n    return nk_checkbox_flags_text(ctx, label, nk_strlen(label), flags, value);\n}\n/*----------------------------------------------------------------\n *\n *                          OPTION\n *\n * --------------------------------------------------------------*/\nNK_API nk_bool\nnk_option_text(struct nk_context *ctx, const char *text, int len, nk_bool is_active)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return is_active;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return (int)state;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active,\n        text, len, NK_TOGGLE_OPTION, &style->option, in, style->font, NK_WIDGET_LEFT, NK_TEXT_LEFT);\n    return is_active;\n}\nNK_API nk_bool\nnk_option_text_align(struct nk_context *ctx, const char *text, int len, nk_bool is_active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return is_active;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return (int)state;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active,\n        text, len, NK_TOGGLE_OPTION, &style->option, in, style->font, widget_alignment, text_alignment);\n    return is_active;\n}\nNK_API nk_bool\nnk_radio_text(struct nk_context *ctx, const char *text, int len, nk_bool *active)\n{\n    int old_value;\n    NK_ASSERT(ctx);\n    NK_ASSERT(text);\n    NK_ASSERT(active);\n    if (!ctx || !text || !active) return 0;\n    old_value = *active;\n    *active = nk_option_text(ctx, text, len, old_value);\n    return old_value != *active;\n}\nNK_API nk_bool\nnk_radio_text_align(struct nk_context *ctx, const char *text, int len, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    int old_value;\n    NK_ASSERT(ctx);\n    NK_ASSERT(text);\n    NK_ASSERT(active);\n    if (!ctx || !text || !active) return 0;\n    old_value = *active;\n    *active = nk_option_text_align(ctx, text, len, old_value, widget_alignment, text_alignment);\n    return old_value != *active;\n}\nNK_API nk_bool\nnk_option_label(struct nk_context *ctx, const char *label, nk_bool active)\n{\n    return nk_option_text(ctx, label, nk_strlen(label), active);\n}\nNK_API nk_bool\nnk_option_label_align(struct nk_context *ctx, const char *label, nk_bool active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    return nk_option_text_align(ctx, label, nk_strlen(label), active, widget_alignment, text_alignment);\n}\nNK_API nk_bool\nnk_radio_label(struct nk_context *ctx, const char *label, nk_bool *active)\n{\n    return nk_radio_text(ctx, label, nk_strlen(label), active);\n}\nNK_API nk_bool\nnk_radio_label_align(struct nk_context *ctx, const char *label, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    return nk_radio_text_align(ctx, label, nk_strlen(label), active, widget_alignment, text_alignment);\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                              SELECTABLE\n *\n * ===============================================================*/\nNK_LIB void\nnk_draw_selectable(struct nk_command_buffer *out,\n    nk_flags state, const struct nk_style_selectable *style, nk_bool active,\n    const struct nk_rect *bounds,\n    const struct nk_rect *icon, const struct nk_image *img, enum nk_symbol_type sym,\n    const char *string, int len, nk_flags align, const struct nk_user_font *font)\n{\n    const struct nk_style_item *background;\n    struct nk_text text;\n    text.padding = style->padding;\n\n    /* select correct colors/images */\n    if (!active) {\n        if (state & NK_WIDGET_STATE_ACTIVED) {\n            background = &style->pressed;\n            text.text = style->text_pressed;\n        } else if (state & NK_WIDGET_STATE_HOVER) {\n            background = &style->hover;\n            text.text = style->text_hover;\n        } else {\n            background = &style->normal;\n            text.text = style->text_normal;\n        }\n    } else {\n        if (state & NK_WIDGET_STATE_ACTIVED) {\n            background = &style->pressed_active;\n            text.text = style->text_pressed_active;\n        } else if (state & NK_WIDGET_STATE_HOVER) {\n            background = &style->hover_active;\n            text.text = style->text_hover_active;\n        } else {\n            background = &style->normal_active;\n            text.text = style->text_normal_active;\n        }\n    }\n\n    text.text = nk_rgb_factor(text.text, style->color_factor);\n\n    /* draw selectable background and text */\n    switch (background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            text.background = background->data.color;\n            nk_fill_rect(out, *bounds, style->rounding, background->data.color);\n            break;\n    }\n    if (icon) {\n        if (img) nk_draw_image(out, *icon, img, nk_rgb_factor(nk_white, style->color_factor));\n        else nk_draw_symbol(out, sym, *icon, text.background, text.text, 1, font);\n    }\n    nk_widget_text(out, *bounds, string, len, &text, align, font);\n}\nNK_LIB nk_bool\nnk_do_selectable(nk_flags *state, struct nk_command_buffer *out,\n    struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value,\n    const struct nk_style_selectable *style, const struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    int old_value;\n    struct nk_rect touch;\n\n    NK_ASSERT(state);\n    NK_ASSERT(out);\n    NK_ASSERT(str);\n    NK_ASSERT(len);\n    NK_ASSERT(value);\n    NK_ASSERT(style);\n    NK_ASSERT(font);\n\n    if (!state || !out || !str || !len || !value || !style || !font) return 0;\n    old_value = *value;\n\n    /* remove padding */\n    touch.x = bounds.x - style->touch_padding.x;\n    touch.y = bounds.y - style->touch_padding.y;\n    touch.w = bounds.w + style->touch_padding.x * 2;\n    touch.h = bounds.h + style->touch_padding.y * 2;\n\n    /* update button */\n    if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))\n        *value = !(*value);\n\n    /* draw selectable */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_selectable(out, *state, style, *value, &bounds, 0,0,NK_SYMBOL_NONE, str, len, align, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return old_value != *value;\n}\nNK_LIB nk_bool\nnk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out,\n    struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value,\n    const struct nk_image *img, const struct nk_style_selectable *style,\n    const struct nk_input *in, const struct nk_user_font *font)\n{\n    nk_bool old_value;\n    struct nk_rect touch;\n    struct nk_rect icon;\n\n    NK_ASSERT(state);\n    NK_ASSERT(out);\n    NK_ASSERT(str);\n    NK_ASSERT(len);\n    NK_ASSERT(value);\n    NK_ASSERT(style);\n    NK_ASSERT(font);\n\n    if (!state || !out || !str || !len || !value || !style || !font) return 0;\n    old_value = *value;\n\n    /* toggle behavior */\n    touch.x = bounds.x - style->touch_padding.x;\n    touch.y = bounds.y - style->touch_padding.y;\n    touch.w = bounds.w + style->touch_padding.x * 2;\n    touch.h = bounds.h + style->touch_padding.y * 2;\n    if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))\n        *value = !(*value);\n\n    icon.y = bounds.y + style->padding.y;\n    icon.w = icon.h = bounds.h - 2 * style->padding.y;\n    if (align & NK_TEXT_ALIGN_LEFT) {\n        icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);\n        icon.x = NK_MAX(icon.x, 0);\n    } else icon.x = bounds.x + 2 * style->padding.x;\n\n    icon.x += style->image_padding.x;\n    icon.y += style->image_padding.y;\n    icon.w -= 2 * style->image_padding.x;\n    icon.h -= 2 * style->image_padding.y;\n\n    /* draw selectable */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_selectable(out, *state, style, *value, &bounds, &icon, img, NK_SYMBOL_NONE, str, len, align, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return old_value != *value;\n}\nNK_LIB nk_bool\nnk_do_selectable_symbol(nk_flags *state, struct nk_command_buffer *out,\n    struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value,\n    enum nk_symbol_type sym, const struct nk_style_selectable *style,\n    const struct nk_input *in, const struct nk_user_font *font)\n{\n    int old_value;\n    struct nk_rect touch;\n    struct nk_rect icon;\n\n    NK_ASSERT(state);\n    NK_ASSERT(out);\n    NK_ASSERT(str);\n    NK_ASSERT(len);\n    NK_ASSERT(value);\n    NK_ASSERT(style);\n    NK_ASSERT(font);\n\n    if (!state || !out || !str || !len || !value || !style || !font) return 0;\n    old_value = *value;\n\n    /* toggle behavior */\n    touch.x = bounds.x - style->touch_padding.x;\n    touch.y = bounds.y - style->touch_padding.y;\n    touch.w = bounds.w + style->touch_padding.x * 2;\n    touch.h = bounds.h + style->touch_padding.y * 2;\n    if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))\n        *value = !(*value);\n\n    icon.y = bounds.y + style->padding.y;\n    icon.w = icon.h = bounds.h - 2 * style->padding.y;\n    if (align & NK_TEXT_ALIGN_LEFT) {\n        icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);\n        icon.x = NK_MAX(icon.x, 0);\n    } else icon.x = bounds.x + 2 * style->padding.x;\n\n    icon.x += style->image_padding.x;\n    icon.y += style->image_padding.y;\n    icon.w -= 2 * style->image_padding.x;\n    icon.h -= 2 * style->image_padding.y;\n\n    /* draw selectable */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_selectable(out, *state, style, *value, &bounds, &icon, 0, sym, str, len, align, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return old_value != *value;\n}\n\nNK_API nk_bool\nnk_selectable_text(struct nk_context *ctx, const char *str, int len,\n    nk_flags align, nk_bool *value)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    enum nk_widget_layout_states state;\n    struct nk_rect bounds;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(value);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !value)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n    style = &ctx->style;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds,\n                str, len, align, value, &style->selectable, in, style->font);\n}\nNK_API nk_bool\nnk_selectable_image_text(struct nk_context *ctx, struct nk_image img,\n    const char *str, int len, nk_flags align, nk_bool *value)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    enum nk_widget_layout_states state;\n    struct nk_rect bounds;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(value);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !value)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n    style = &ctx->style;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_selectable_image(&ctx->last_widget_state, &win->buffer, bounds,\n                str, len, align, value, &img, &style->selectable, in, style->font);\n}\nNK_API nk_bool\nnk_selectable_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *str, int len, nk_flags align, nk_bool *value)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    enum nk_widget_layout_states state;\n    struct nk_rect bounds;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(value);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !value)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n    style = &ctx->style;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_selectable_symbol(&ctx->last_widget_state, &win->buffer, bounds,\n                str, len, align, value, sym, &style->selectable, in, style->font);\n}\nNK_API nk_bool\nnk_selectable_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *title, nk_flags align, nk_bool *value)\n{\n    return nk_selectable_symbol_text(ctx, sym, title, nk_strlen(title), align, value);\n}\nNK_API nk_bool nk_select_text(struct nk_context *ctx, const char *str, int len,\n    nk_flags align, nk_bool value)\n{\n    nk_selectable_text(ctx, str, len, align, &value);return value;\n}\nNK_API nk_bool nk_selectable_label(struct nk_context *ctx, const char *str, nk_flags align, nk_bool *value)\n{\n    return nk_selectable_text(ctx, str, nk_strlen(str), align, value);\n}\nNK_API nk_bool nk_selectable_image_label(struct nk_context *ctx,struct nk_image img,\n    const char *str, nk_flags align, nk_bool *value)\n{\n    return nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, value);\n}\nNK_API nk_bool nk_select_label(struct nk_context *ctx, const char *str, nk_flags align, nk_bool value)\n{\n    nk_selectable_text(ctx, str, nk_strlen(str), align, &value);return value;\n}\nNK_API nk_bool nk_select_image_label(struct nk_context *ctx, struct nk_image img,\n    const char *str, nk_flags align, nk_bool value)\n{\n    nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, &value);return value;\n}\nNK_API nk_bool nk_select_image_text(struct nk_context *ctx, struct nk_image img,\n    const char *str, int len, nk_flags align, nk_bool value)\n{\n    nk_selectable_image_text(ctx, img, str, len, align, &value);return value;\n}\nNK_API nk_bool\nnk_select_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *title, int title_len, nk_flags align, nk_bool value)\n{\n    nk_selectable_symbol_text(ctx, sym, title, title_len, align, &value);return value;\n}\nNK_API nk_bool\nnk_select_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *title, nk_flags align, nk_bool value)\n{\n    return nk_select_symbol_text(ctx, sym, title, nk_strlen(title), align, value);\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                              SLIDER\n *\n * ===============================================================*/\nNK_LIB float\nnk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor,\n    struct nk_rect *visual_cursor, struct nk_input *in,\n    struct nk_rect bounds, float slider_min, float slider_max, float slider_value,\n    float slider_step, float slider_steps)\n{\n    int left_mouse_down;\n    int left_mouse_click_in_cursor;\n\n    /* check if visual cursor is being dragged */\n    nk_widget_state_reset(state);\n    left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;\n    left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in,\n            NK_BUTTON_LEFT, *visual_cursor, nk_true);\n\n    if (left_mouse_down && left_mouse_click_in_cursor) {\n        float ratio = 0;\n        const float d = in->mouse.pos.x - (visual_cursor->x+visual_cursor->w*0.5f);\n        const float pxstep = bounds.w / slider_steps;\n\n        /* only update value if the next slider step is reached */\n        *state = NK_WIDGET_STATE_ACTIVE;\n        if (NK_ABS(d) >= pxstep) {\n            const float steps = (float)((int)(NK_ABS(d) / pxstep));\n            slider_value += (d > 0) ? (slider_step*steps) : -(slider_step*steps);\n            slider_value = NK_CLAMP(slider_min, slider_value, slider_max);\n            ratio = (slider_value - slider_min)/slider_step;\n            logical_cursor->x = bounds.x + (logical_cursor->w * ratio);\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = logical_cursor->x;\n        }\n    }\n\n    /* slider widget state */\n    if (nk_input_is_mouse_hovering_rect(in, bounds))\n        *state = NK_WIDGET_STATE_HOVERED;\n    if (*state & NK_WIDGET_STATE_HOVER &&\n        !nk_input_is_mouse_prev_hovering_rect(in, bounds))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, bounds))\n        *state |= NK_WIDGET_STATE_LEFT;\n    return slider_value;\n}\nNK_LIB void\nnk_draw_slider(struct nk_command_buffer *out, nk_flags state,\n    const struct nk_style_slider *style, const struct nk_rect *bounds,\n    const struct nk_rect *visual_cursor, float min, float value, float max)\n{\n    struct nk_rect fill;\n    struct nk_rect bar;\n    const struct nk_style_item *background;\n\n    /* select correct slider images/colors */\n    struct nk_color bar_color;\n    const struct nk_style_item *cursor;\n\n    NK_UNUSED(min);\n    NK_UNUSED(max);\n    NK_UNUSED(value);\n\n    if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->active;\n        bar_color = style->bar_active;\n        cursor = &style->cursor_active;\n    } else if (state & NK_WIDGET_STATE_HOVER) {\n        background = &style->hover;\n        bar_color = style->bar_hover;\n        cursor = &style->cursor_hover;\n    } else {\n        background = &style->normal;\n        bar_color = style->bar_normal;\n        cursor = &style->cursor_normal;\n    }\n\n    /* calculate slider background bar */\n    bar.x = bounds->x;\n    bar.y = (visual_cursor->y + visual_cursor->h/2) - bounds->h/12;\n    bar.w = bounds->w;\n    bar.h = bounds->h/6;\n\n    /* filled background bar style */\n    fill.w = (visual_cursor->x + (visual_cursor->w/2.0f)) - bar.x;\n    fill.x = bar.x;\n    fill.y = bar.y;\n    fill.h = bar.h;\n\n    /* draw background */\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));\n            nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));\n            break;\n    }\n\n    /* draw slider bar */\n    nk_fill_rect(out, bar, style->rounding, nk_rgb_factor(bar_color, style->color_factor));\n    nk_fill_rect(out, fill, style->rounding, nk_rgb_factor(style->bar_filled, style->color_factor));\n\n    /* draw cursor */\n    if (cursor->type == NK_STYLE_ITEM_IMAGE)\n        nk_draw_image(out, *visual_cursor, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));\n    else\n        nk_fill_circle(out, *visual_cursor, nk_rgb_factor(cursor->data.color, style->color_factor));\n}\nNK_LIB float\nnk_do_slider(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    float min, float val, float max, float step,\n    const struct nk_style_slider *style, struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    float slider_range;\n    float slider_min;\n    float slider_max;\n    float slider_value;\n    float slider_steps;\n    float cursor_offset;\n\n    struct nk_rect visual_cursor;\n    struct nk_rect logical_cursor;\n\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    if (!out || !style)\n        return 0;\n\n    /* remove padding from slider bounds */\n    bounds.x = bounds.x + style->padding.x;\n    bounds.y = bounds.y + style->padding.y;\n    bounds.h = NK_MAX(bounds.h, 2*style->padding.y);\n    bounds.w = NK_MAX(bounds.w, 2*style->padding.x + style->cursor_size.x);\n    bounds.w -= 2 * style->padding.x;\n    bounds.h -= 2 * style->padding.y;\n\n    /* optional buttons */\n    if (style->show_buttons) {\n        nk_flags ws;\n        struct nk_rect button;\n        button.y = bounds.y;\n        button.w = bounds.h;\n        button.h = bounds.h;\n\n        /* decrement button */\n        button.x = bounds.x;\n        if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, NK_BUTTON_DEFAULT,\n            &style->dec_button, in, font))\n            val -= step;\n\n        /* increment button */\n        button.x = (bounds.x + bounds.w) - button.w;\n        if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, NK_BUTTON_DEFAULT,\n            &style->inc_button, in, font))\n            val += step;\n\n        bounds.x = bounds.x + button.w + style->spacing.x;\n        bounds.w = bounds.w - (2*button.w + 2*style->spacing.x);\n    }\n\n    /* remove one cursor size to support visual cursor */\n    bounds.x += style->cursor_size.x*0.5f;\n    bounds.w -= style->cursor_size.x;\n\n    /* make sure the provided values are correct */\n    slider_max = NK_MAX(min, max);\n    slider_min = NK_MIN(min, max);\n    slider_value = NK_CLAMP(slider_min, val, slider_max);\n    slider_range = slider_max - slider_min;\n    slider_steps = slider_range / step;\n    cursor_offset = (slider_value - slider_min) / step;\n\n    /* calculate cursor\n    Basically you have two cursors. One for visual representation and interaction\n    and one for updating the actual cursor value. */\n    logical_cursor.h = bounds.h;\n    logical_cursor.w = bounds.w / slider_steps;\n    logical_cursor.x = bounds.x + (logical_cursor.w * cursor_offset);\n    logical_cursor.y = bounds.y;\n\n    visual_cursor.h = style->cursor_size.y;\n    visual_cursor.w = style->cursor_size.x;\n    visual_cursor.y = (bounds.y + bounds.h*0.5f) - visual_cursor.h*0.5f;\n    visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;\n\n    slider_value = nk_slider_behavior(state, &logical_cursor, &visual_cursor,\n        in, bounds, slider_min, slider_max, slider_value, step, slider_steps);\n    visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;\n\n    /* draw slider */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_slider(out, *state, style, &bounds, &visual_cursor, slider_min, slider_value, slider_max);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return slider_value;\n}\nNK_API nk_bool\nnk_slider_float(struct nk_context *ctx, float min_value, float *value, float max_value,\n    float value_step)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    struct nk_input *in;\n    const struct nk_style *style;\n\n    int ret = 0;\n    float old_value;\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    NK_ASSERT(value);\n    if (!ctx || !ctx->current || !ctx->current->layout || !value)\n        return ret;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return ret;\n    in = (/*state == NK_WIDGET_ROM || */ state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n\n    old_value = *value;\n    *value = nk_do_slider(&ctx->last_widget_state, &win->buffer, bounds, min_value,\n                old_value, max_value, value_step, &style->slider, in, style->font);\n    return (old_value > *value || old_value < *value);\n}\nNK_API float\nnk_slide_float(struct nk_context *ctx, float min, float val, float max, float step)\n{\n    nk_slider_float(ctx, min, &val, max, step); return val;\n}\nNK_API int\nnk_slide_int(struct nk_context *ctx, int min, int val, int max, int step)\n{\n    float value = (float)val;\n    nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);\n    return (int)value;\n}\nNK_API nk_bool\nnk_slider_int(struct nk_context *ctx, int min, int *val, int max, int step)\n{\n    int ret;\n    float value = (float)*val;\n    ret = nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);\n    *val =  (int)value;\n    return ret;\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                               KNOB\n *\n * ===============================================================*/\n\nNK_LIB float\nnk_knob_behavior(nk_flags *state, struct nk_input *in,\n    struct nk_rect bounds, float knob_min, float knob_max, float knob_value,\n    float knob_step, float knob_steps,\n    enum nk_heading zero_direction, float dead_zone_percent)\n{\n    struct nk_vec2 origin;\n    float angle = 0.0f;\n    origin.x = bounds.x + (bounds.w / 2);\n    origin.y = bounds.y + (bounds.h / 2);\n\n    nk_widget_state_reset(state);\n\n    /* handle click and drag input */\n    if(in &&\n       in->mouse.buttons[NK_BUTTON_LEFT].down &&\n       nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, bounds, nk_true)){\n        /* calculate angle from origin and rotate */\n        const float direction_rads[4] = {\n            NK_PI * 2.5f, /* 90  NK_UP */\n            NK_PI * 2.0f, /* 0   NK_RIGHT */\n            NK_PI * 1.5f, /* 270 NK_DOWN */\n            NK_PI,        /* 180 NK_LEFT */\n        };\n        *state = NK_WIDGET_STATE_ACTIVE;\n\n        angle = NK_ATAN2(in->mouse.pos.y - origin.y, in->mouse.pos.x - origin.x) + direction_rads[zero_direction];\n        angle -= (angle > NK_PI * 2) ? NK_PI * 3 : NK_PI;\n\n        /* account for dead space applied when drawing */\n        angle *= 1.0f / (1.0f - dead_zone_percent);\n        angle = NK_CLAMP(-NK_PI, angle, NK_PI);\n\n        /* convert -pi -> pi range to 0.0 -> 1.0 */\n        angle = (angle + NK_PI) / (NK_PI * 2);\n\n        /* click to closest step */\n        knob_value = knob_min + ( (int)(angle * knob_steps + (knob_step / 2)) ) * knob_step;\n        knob_value = NK_CLAMP(knob_min, knob_value, knob_max);\n    }\n\n    /* knob widget state */\n    if (nk_input_is_mouse_hovering_rect(in, bounds)){\n        *state = NK_WIDGET_STATE_HOVERED;\n        /* handle scroll and arrow inputs */\n        if (in->mouse.scroll_delta.y > 0 ||\n           (in->keyboard.keys[NK_KEY_UP].down && in->keyboard.keys[NK_KEY_UP].clicked)) {\n            knob_value += knob_step;\n        }\n\n        if (in->mouse.scroll_delta.y < 0 ||\n           (in->keyboard.keys[NK_KEY_DOWN].down && in->keyboard.keys[NK_KEY_DOWN].clicked)) {\n            knob_value -= knob_step;\n        }\n        /* easiest way to disable scrolling of parent panels..knob eats scrolling */\n        in->mouse.scroll_delta.y = 0;\n        knob_value = NK_CLAMP(knob_min, knob_value, knob_max);\n    }\n    if (*state & NK_WIDGET_STATE_HOVER &&\n        !nk_input_is_mouse_prev_hovering_rect(in, bounds))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, bounds))\n        *state |= NK_WIDGET_STATE_LEFT;\n\n    return knob_value;\n}\nNK_LIB void\nnk_draw_knob(struct nk_command_buffer *out, nk_flags state,\n    const struct nk_style_knob *style, const struct nk_rect *bounds, float min, float value, float max,\n    enum nk_heading zero_direction, float dead_zone_percent)\n{\n    const struct nk_style_item *background;\n    struct nk_color knob_color, cursor;\n\n    NK_UNUSED(min);\n    NK_UNUSED(max);\n    NK_UNUSED(value);\n\n    if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->active;\n        knob_color = style->knob_active;\n        cursor = style->cursor_active;\n    } else if (state & NK_WIDGET_STATE_HOVER) {\n        background = &style->hover;\n        knob_color = style->knob_hover;\n        cursor = style->cursor_hover;\n    } else {\n        background = &style->normal;\n        knob_color = style->knob_normal;\n        cursor = style->cursor_normal;\n    }\n\n    /* draw background */\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *bounds, 0, nk_rgb_factor(background->data.color, style->color_factor));\n            nk_stroke_rect(out, *bounds, 0, style->border, nk_rgb_factor(style->border_color, style->color_factor));\n            break;\n    }\n\n    /* draw knob */\n    nk_fill_circle(out, *bounds, nk_rgb_factor(knob_color, style->color_factor));\n    if(style->knob_border > 0){\n        struct nk_rect border_bounds = *bounds;\n        border_bounds.x += style->knob_border / 2;\n        border_bounds.y += style->knob_border / 2;\n        border_bounds.w -= style->knob_border;\n        border_bounds.h -= style->knob_border;\n        nk_stroke_circle(out, border_bounds, style->knob_border, nk_rgb_factor(style->knob_border_color, style->color_factor));\n    }\n    { /* calculate cursor line cords */\n    float half_circle_size = (bounds->w / 2);\n    float angle = (value - min) / (max - min);\n    float alive_zone =  1.0f - dead_zone_percent;\n    struct nk_vec2 cursor_start, cursor_end;\n    const float direction_rads[4] = {\n        NK_PI * 1.5f, /* 90  NK_UP */\n        0.0f,         /* 0   NK_RIGHT */\n        NK_PI * 0.5f, /* 270 NK_DOWN */\n        NK_PI,        /* 180 NK_LEFT */\n    };\n    /* calculate + apply dead zone */\n    angle = (angle * alive_zone) + (dead_zone_percent / 2);\n\n    /* percentage 0.0 -> 1.0 to radians, rads are 0.0 to (2*pi) NOT -pi to pi */\n    angle *= NK_PI * 2;\n\n    /* apply zero angle */\n    angle += direction_rads[zero_direction];\n    if(angle > NK_PI * 2)\n        angle -= NK_PI * 2;\n\n    cursor_start.x = bounds->x + half_circle_size + (angle > NK_PI);\n    cursor_start.y = bounds->y + half_circle_size + (angle < NK_PI_HALF || angle > (NK_PI * 1.5f));\n\n    cursor_end.x = cursor_start.x + (half_circle_size * NK_COS(angle));\n    cursor_end.y = cursor_start.y + (half_circle_size * NK_SIN(angle));\n\n    /* cut off half of the cursor */\n    cursor_start.x = (cursor_start.x + cursor_end.x) / 2;\n    cursor_start.y = (cursor_start.y + cursor_end.y) / 2;\n\n    /* draw cursor */\n    nk_stroke_line(out, cursor_start.x, cursor_start.y, cursor_end.x, cursor_end.y, 2, nk_rgb_factor(cursor, style->color_factor));\n    }\n}\nNK_LIB float\nnk_do_knob(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    float min, float val, float max, float step,\n    enum nk_heading zero_direction, float dead_zone_percent,\n    const struct nk_style_knob *style, struct nk_input *in)\n{\n    float knob_range;\n    float knob_min;\n    float knob_max;\n    float knob_value;\n    float knob_steps;\n\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    if (!out || !style)\n        return 0;\n\n    /* remove padding from knob bounds */\n    bounds.y = bounds.y + style->padding.y;\n    bounds.x = bounds.x + style->padding.x;\n    bounds.h = NK_MAX(bounds.h, 2*style->padding.y);\n    bounds.w = NK_MAX(bounds.w, 2*style->padding.x);\n    bounds.w -= 2 * style->padding.x;\n    bounds.h -= 2 * style->padding.y;\n    if(bounds.h < bounds.w){\n        bounds.x += (bounds.w - bounds.h) / 2;\n        bounds.w = bounds.h;\n    }\n\n    /* make sure the provided values are correct */\n    knob_max = NK_MAX(min, max);\n    knob_min = NK_MIN(min, max);\n    knob_value = NK_CLAMP(knob_min, val, knob_max);\n    knob_range = knob_max - knob_min;\n    knob_steps = knob_range / step;\n\n    knob_value = nk_knob_behavior(state, in, bounds, knob_min, knob_max, knob_value, step, knob_steps, zero_direction, dead_zone_percent);\n\n    /* draw knob */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_knob(out, *state, style, &bounds, knob_min, knob_value, knob_max, zero_direction, dead_zone_percent);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return knob_value;\n}\nNK_API nk_bool\nnk_knob_float(struct nk_context *ctx, float min_value, float *value, float max_value,\n    float value_step, enum nk_heading zero_direction, float dead_zone_degrees)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    struct nk_input *in;\n    const struct nk_style *style;\n\n    int ret = 0;\n    float old_value;\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    NK_ASSERT(value);\n    NK_ASSERT(NK_BETWEEN(dead_zone_degrees, 0.0f, 360.0f));\n    if (!ctx || !ctx->current || !ctx->current->layout || !value)\n        return ret;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return ret;\n    in = (state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n\n    old_value = *value;\n    *value = nk_do_knob(&ctx->last_widget_state, &win->buffer, bounds, min_value,\n                old_value, max_value, value_step, zero_direction, dead_zone_degrees / 360.0f, &style->knob, in);\n\n    return (old_value > *value || old_value < *value);\n}\nNK_API nk_bool\nnk_knob_int(struct nk_context *ctx, int min, int *val, int max, int step,\n    enum nk_heading zero_direction, float dead_zone_degrees)\n{\n    int ret;\n    float value = (float)*val;\n    ret = nk_knob_float(ctx, (float)min, &value, (float)max, (float)step, zero_direction, dead_zone_degrees);\n    *val =  (int)value;\n    return ret;\n}\n\n\n\n\n/* ===============================================================\n *\n *                          PROGRESS\n *\n * ===============================================================*/\nNK_LIB nk_size\nnk_progress_behavior(nk_flags *state, struct nk_input *in,\n    struct nk_rect r, struct nk_rect cursor, nk_size max, nk_size value, nk_bool modifiable)\n{\n    int left_mouse_down = 0;\n    int left_mouse_click_in_cursor = 0;\n\n    nk_widget_state_reset(state);\n    if (!in || !modifiable) return value;\n    left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;\n    left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in,\n            NK_BUTTON_LEFT, cursor, nk_true);\n    if (nk_input_is_mouse_hovering_rect(in, r))\n        *state = NK_WIDGET_STATE_HOVERED;\n\n    if (in && left_mouse_down && left_mouse_click_in_cursor) {\n        if (left_mouse_down && left_mouse_click_in_cursor) {\n            float ratio = NK_MAX(0, (float)(in->mouse.pos.x - cursor.x)) / (float)cursor.w;\n            value = (nk_size)NK_CLAMP(0, (float)max * ratio, (float)max);\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor.x + cursor.w/2.0f;\n            *state |= NK_WIDGET_STATE_ACTIVE;\n        }\n    }\n    /* set progressbar widget state */\n    if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, r))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, r))\n        *state |= NK_WIDGET_STATE_LEFT;\n    return value;\n}\nNK_LIB void\nnk_draw_progress(struct nk_command_buffer *out, nk_flags state,\n    const struct nk_style_progress *style, const struct nk_rect *bounds,\n    const struct nk_rect *scursor, nk_size value, nk_size max)\n{\n    const struct nk_style_item *background;\n    const struct nk_style_item *cursor;\n\n    NK_UNUSED(max);\n    NK_UNUSED(value);\n\n    /* select correct colors/images to draw */\n    if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->active;\n        cursor = &style->cursor_active;\n    } else if (state & NK_WIDGET_STATE_HOVER){\n        background = &style->hover;\n        cursor = &style->cursor_hover;\n    } else {\n        background = &style->normal;\n        cursor = &style->cursor_normal;\n    }\n\n    /* draw background */\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));\n            nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));\n            break;\n    }\n\n    /* draw cursor */\n    switch(cursor->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *scursor, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *scursor, &cursor->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *scursor, style->rounding, nk_rgb_factor(cursor->data.color, style->color_factor));\n            nk_stroke_rect(out, *scursor, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));\n            break;\n    }\n}\nNK_LIB nk_size\nnk_do_progress(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    nk_size value, nk_size max, nk_bool modifiable,\n    const struct nk_style_progress *style, struct nk_input *in)\n{\n    float prog_scale;\n    nk_size prog_value;\n    struct nk_rect cursor;\n\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    if (!out || !style) return 0;\n\n    /* calculate progressbar cursor */\n    cursor.w = NK_MAX(bounds.w, 2 * style->padding.x + 2 * style->border);\n    cursor.h = NK_MAX(bounds.h, 2 * style->padding.y + 2 * style->border);\n    cursor = nk_pad_rect(bounds, nk_vec2(style->padding.x + style->border, style->padding.y + style->border));\n    prog_scale = (float)value / (float)max;\n\n    /* update progressbar */\n    prog_value = NK_MIN(value, max);\n    prog_value = nk_progress_behavior(state, in, bounds, cursor,max, prog_value, modifiable);\n    cursor.w = cursor.w * prog_scale;\n\n    /* draw progressbar */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_progress(out, *state, style, &bounds, &cursor, value, max);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return prog_value;\n}\nNK_API nk_bool\nnk_progress(struct nk_context *ctx, nk_size *cur, nk_size max, nk_bool is_modifyable)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_style *style;\n    struct nk_input *in;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n    nk_size old_value;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(cur);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !cur)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    old_value = *cur;\n    *cur = nk_do_progress(&ctx->last_widget_state, &win->buffer, bounds,\n            *cur, max, is_modifyable, &style->progress, in);\n    return (*cur != old_value);\n}\nNK_API nk_size\nnk_prog(struct nk_context *ctx, nk_size cur, nk_size max, nk_bool modifyable)\n{\n    nk_progress(ctx, &cur, max, modifyable);\n    return cur;\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                              SCROLLBAR\n *\n * ===============================================================*/\nNK_LIB float\nnk_scrollbar_behavior(nk_flags *state, struct nk_input *in,\n    int has_scrolling, const struct nk_rect *scroll,\n    const struct nk_rect *cursor, const struct nk_rect *empty0,\n    const struct nk_rect *empty1, float scroll_offset,\n    float target, float scroll_step, enum nk_orientation o)\n{\n    nk_flags ws = 0;\n    int left_mouse_down;\n    unsigned int left_mouse_clicked;\n    int left_mouse_click_in_cursor;\n    float scroll_delta;\n\n    nk_widget_state_reset(state);\n    if (!in) return scroll_offset;\n\n    left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;\n    left_mouse_clicked = in->mouse.buttons[NK_BUTTON_LEFT].clicked;\n    left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,\n        NK_BUTTON_LEFT, *cursor, nk_true);\n    if (nk_input_is_mouse_hovering_rect(in, *scroll))\n        *state = NK_WIDGET_STATE_HOVERED;\n\n    scroll_delta = (o == NK_VERTICAL) ? in->mouse.scroll_delta.y: in->mouse.scroll_delta.x;\n    if (left_mouse_down && left_mouse_click_in_cursor && !left_mouse_clicked) {\n        /* update cursor by mouse dragging */\n        float pixel, delta;\n        *state = NK_WIDGET_STATE_ACTIVE;\n        if (o == NK_VERTICAL) {\n            float cursor_y;\n            pixel = in->mouse.delta.y;\n            delta = (pixel / scroll->h) * target;\n            scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->h);\n            cursor_y = scroll->y + ((scroll_offset/target) * scroll->h);\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = cursor_y + cursor->h/2.0f;\n        } else {\n            float cursor_x;\n            pixel = in->mouse.delta.x;\n            delta = (pixel / scroll->w) * target;\n            scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->w);\n            cursor_x = scroll->x + ((scroll_offset/target) * scroll->w);\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor_x + cursor->w/2.0f;\n        }\n    } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_UP) && o == NK_VERTICAL && has_scrolling)||\n            nk_button_behavior(&ws, *empty0, in, NK_BUTTON_DEFAULT)) {\n        /* scroll page up by click on empty space or shortcut */\n        if (o == NK_VERTICAL)\n            scroll_offset = NK_MAX(0, scroll_offset - scroll->h);\n        else scroll_offset = NK_MAX(0, scroll_offset - scroll->w);\n    } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_DOWN) && o == NK_VERTICAL && has_scrolling) ||\n        nk_button_behavior(&ws, *empty1, in, NK_BUTTON_DEFAULT)) {\n        /* scroll page down by click on empty space or shortcut */\n        if (o == NK_VERTICAL)\n            scroll_offset = NK_MIN(scroll_offset + scroll->h, target - scroll->h);\n        else scroll_offset = NK_MIN(scroll_offset + scroll->w, target - scroll->w);\n    } else if (has_scrolling) {\n        if ((scroll_delta < 0 || (scroll_delta > 0))) {\n            /* update cursor by mouse scrolling */\n            scroll_offset = scroll_offset + scroll_step * (-scroll_delta);\n            if (o == NK_VERTICAL)\n                scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->h);\n            else scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->w);\n        } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_START)) {\n            /* update cursor to the beginning  */\n            if (o == NK_VERTICAL) scroll_offset = 0;\n        } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_END)) {\n            /* update cursor to the end */\n            if (o == NK_VERTICAL) scroll_offset = target - scroll->h;\n        }\n    }\n    if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *scroll))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, *scroll))\n        *state |= NK_WIDGET_STATE_LEFT;\n    return scroll_offset;\n}\nNK_LIB void\nnk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state,\n    const struct nk_style_scrollbar *style, const struct nk_rect *bounds,\n    const struct nk_rect *scroll)\n{\n    const struct nk_style_item *background;\n    const struct nk_style_item *cursor;\n\n    /* select correct colors/images to draw */\n    if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->active;\n        cursor = &style->cursor_active;\n    } else if (state & NK_WIDGET_STATE_HOVER) {\n        background = &style->hover;\n        cursor = &style->cursor_hover;\n    } else {\n        background = &style->normal;\n        cursor = &style->cursor_normal;\n    }\n\n    /* draw background */\n    switch (background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *bounds, &background->data.image, nk_white);\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_white);\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *bounds, style->rounding, background->data.color);\n            nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);\n            break;\n    }\n\n    /* draw cursor */\n    switch (cursor->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *scroll, &cursor->data.image, nk_white);\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *scroll, &cursor->data.slice, nk_white);\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *scroll, style->rounding_cursor, cursor->data.color);\n            nk_stroke_rect(out, *scroll, style->rounding_cursor, style->border_cursor, style->cursor_border_color);\n            break;\n    }\n}\nNK_LIB float\nnk_do_scrollbarv(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling,\n    float offset, float target, float step, float button_pixel_inc,\n    const struct nk_style_scrollbar *style, struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    struct nk_rect empty_north;\n    struct nk_rect empty_south;\n    struct nk_rect cursor;\n\n    float scroll_step;\n    float scroll_offset;\n    float scroll_off;\n    float scroll_ratio;\n\n    NK_ASSERT(out);\n    NK_ASSERT(style);\n    NK_ASSERT(state);\n    if (!out || !style) return 0;\n\n    scroll.w = NK_MAX(scroll.w, 1);\n    scroll.h = NK_MAX(scroll.h, 0);\n    if (target <= scroll.h) return 0;\n\n    /* optional scrollbar buttons */\n    if (style->show_buttons) {\n        nk_flags ws;\n        float scroll_h;\n        struct nk_rect button;\n\n        button.x = scroll.x;\n        button.w = scroll.w;\n        button.h = scroll.w;\n\n        scroll_h = NK_MAX(scroll.h - 2 * button.h,0);\n        scroll_step = NK_MIN(step, button_pixel_inc);\n\n        /* decrement button */\n        button.y = scroll.y;\n        if (nk_do_button_symbol(&ws, out, button, style->dec_symbol,\n            NK_BUTTON_REPEATER, &style->dec_button, in, font))\n            offset = offset - scroll_step;\n\n        /* increment button */\n        button.y = scroll.y + scroll.h - button.h;\n        if (nk_do_button_symbol(&ws, out, button, style->inc_symbol,\n            NK_BUTTON_REPEATER, &style->inc_button, in, font))\n            offset = offset + scroll_step;\n\n        scroll.y = scroll.y + button.h;\n        scroll.h = scroll_h;\n    }\n\n    /* calculate scrollbar constants */\n    scroll_step = NK_MIN(step, scroll.h);\n    scroll_offset = NK_CLAMP(0, offset, target - scroll.h);\n    scroll_ratio = scroll.h / target;\n    scroll_off = scroll_offset / target;\n\n    /* calculate scrollbar cursor bounds */\n    cursor.h = NK_MAX((scroll_ratio * scroll.h) - (2*style->border + 2*style->padding.y), 0);\n    cursor.y = scroll.y + (scroll_off * scroll.h) + style->border + style->padding.y;\n    cursor.w = scroll.w - (2 * style->border + 2 * style->padding.x);\n    cursor.x = scroll.x + style->border + style->padding.x;\n\n    /* calculate empty space around cursor */\n    empty_north.x = scroll.x;\n    empty_north.y = scroll.y;\n    empty_north.w = scroll.w;\n    empty_north.h = NK_MAX(cursor.y - scroll.y, 0);\n\n    empty_south.x = scroll.x;\n    empty_south.y = cursor.y + cursor.h;\n    empty_south.w = scroll.w;\n    empty_south.h = NK_MAX((scroll.y + scroll.h) - (cursor.y + cursor.h), 0);\n\n    /* update scrollbar */\n    scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor,\n        &empty_north, &empty_south, scroll_offset, target, scroll_step, NK_VERTICAL);\n    scroll_off = scroll_offset / target;\n    cursor.y = scroll.y + (scroll_off * scroll.h) + style->border_cursor + style->padding.y;\n\n    /* draw scrollbar */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_scrollbar(out, *state, style, &scroll, &cursor);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return scroll_offset;\n}\nNK_LIB float\nnk_do_scrollbarh(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling,\n    float offset, float target, float step, float button_pixel_inc,\n    const struct nk_style_scrollbar *style, struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    struct nk_rect cursor;\n    struct nk_rect empty_west;\n    struct nk_rect empty_east;\n\n    float scroll_step;\n    float scroll_offset;\n    float scroll_off;\n    float scroll_ratio;\n\n    NK_ASSERT(out);\n    NK_ASSERT(style);\n    if (!out || !style) return 0;\n\n    /* scrollbar background */\n    scroll.h = NK_MAX(scroll.h, 1);\n    scroll.w = NK_MAX(scroll.w, 2 * scroll.h);\n    if (target <= scroll.w) return 0;\n\n    /* optional scrollbar buttons */\n    if (style->show_buttons) {\n        nk_flags ws;\n        float scroll_w;\n        struct nk_rect button;\n        button.y = scroll.y;\n        button.w = scroll.h;\n        button.h = scroll.h;\n\n        scroll_w = scroll.w - 2 * button.w;\n        scroll_step = NK_MIN(step, button_pixel_inc);\n\n        /* decrement button */\n        button.x = scroll.x;\n        if (nk_do_button_symbol(&ws, out, button, style->dec_symbol,\n            NK_BUTTON_REPEATER, &style->dec_button, in, font))\n            offset = offset - scroll_step;\n\n        /* increment button */\n        button.x = scroll.x + scroll.w - button.w;\n        if (nk_do_button_symbol(&ws, out, button, style->inc_symbol,\n            NK_BUTTON_REPEATER, &style->inc_button, in, font))\n            offset = offset + scroll_step;\n\n        scroll.x = scroll.x + button.w;\n        scroll.w = scroll_w;\n    }\n\n    /* calculate scrollbar constants */\n    scroll_step = NK_MIN(step, scroll.w);\n    scroll_offset = NK_CLAMP(0, offset, target - scroll.w);\n    scroll_ratio = scroll.w / target;\n    scroll_off = scroll_offset / target;\n\n    /* calculate cursor bounds */\n    cursor.w = (scroll_ratio * scroll.w) - (2*style->border + 2*style->padding.x);\n    cursor.x = scroll.x + (scroll_off * scroll.w) + style->border + style->padding.x;\n    cursor.h = scroll.h - (2 * style->border + 2 * style->padding.y);\n    cursor.y = scroll.y + style->border + style->padding.y;\n\n    /* calculate empty space around cursor */\n    empty_west.x = scroll.x;\n    empty_west.y = scroll.y;\n    empty_west.w = cursor.x - scroll.x;\n    empty_west.h = scroll.h;\n\n    empty_east.x = cursor.x + cursor.w;\n    empty_east.y = scroll.y;\n    empty_east.w = (scroll.x + scroll.w) - (cursor.x + cursor.w);\n    empty_east.h = scroll.h;\n\n    /* update scrollbar */\n    scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor,\n        &empty_west, &empty_east, scroll_offset, target, scroll_step, NK_HORIZONTAL);\n    scroll_off = scroll_offset / target;\n    cursor.x = scroll.x + (scroll_off * scroll.w);\n\n    /* draw scrollbar */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_scrollbar(out, *state, style, &scroll, &cursor);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return scroll_offset;\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                          TEXT EDITOR\n *\n * ===============================================================*/\n/* stb_textedit.h - v1.8  - public domain - Sean Barrett */\nstruct nk_text_find {\n   float x,y;    /* position of n'th character */\n   float height; /* height of line */\n   int first_char, length; /* first char of row, and length */\n   int prev_first;  /*_ first char of previous row */\n};\n\nstruct nk_text_edit_row {\n   float x0,x1;\n   /* starting x location, end x location (allows for align=right, etc) */\n   float baseline_y_delta;\n   /* position of baseline relative to previous row's baseline*/\n   float ymin,ymax;\n   /* height of row above and below baseline */\n   int num_chars;\n};\n\n/* forward declarations */\nNK_INTERN void nk_textedit_makeundo_delete(struct nk_text_edit*, int, int);\nNK_INTERN void nk_textedit_makeundo_insert(struct nk_text_edit*, int, int);\nNK_INTERN void nk_textedit_makeundo_replace(struct nk_text_edit*, int, int, int);\n#define NK_TEXT_HAS_SELECTION(s)   ((s)->select_start != (s)->select_end)\n\nNK_INTERN float\nnk_textedit_get_width(const struct nk_text_edit *edit, int line_start, int char_id,\n    const struct nk_user_font *font)\n{\n    int len = 0;\n    nk_rune unicode = 0;\n    const char *str = nk_str_at_const(&edit->string, line_start + char_id, &unicode, &len);\n    return font->width(font->userdata, font->height, str, len);\n}\nNK_INTERN void\nnk_textedit_layout_row(struct nk_text_edit_row *r, struct nk_text_edit *edit,\n    int line_start_id, float row_height, const struct nk_user_font *font)\n{\n    int l;\n    int glyphs = 0;\n    nk_rune unicode;\n    const char *remaining;\n    int len = nk_str_len_char(&edit->string);\n    const char *end = nk_str_get_const(&edit->string) + len;\n    const char *text = nk_str_at_const(&edit->string, line_start_id, &unicode, &l);\n    const struct nk_vec2 size = nk_text_calculate_text_bounds(font,\n        text, (int)(end - text), row_height, &remaining, 0, &glyphs, NK_STOP_ON_NEW_LINE);\n\n    r->x0 = 0.0f;\n    r->x1 = size.x;\n    r->baseline_y_delta = size.y;\n    r->ymin = 0.0f;\n    r->ymax = size.y;\n    r->num_chars = glyphs;\n}\nNK_INTERN int\nnk_textedit_locate_coord(struct nk_text_edit *edit, float x, float y,\n    const struct nk_user_font *font, float row_height)\n{\n    struct nk_text_edit_row r;\n    int n = edit->string.len;\n    float base_y = 0, prev_x;\n    int i=0, k;\n\n    r.x0 = r.x1 = 0;\n    r.ymin = r.ymax = 0;\n    r.num_chars = 0;\n\n    /* search rows to find one that straddles 'y' */\n    while (i < n) {\n        nk_textedit_layout_row(&r, edit, i, row_height, font);\n        if (r.num_chars <= 0)\n            return n;\n\n        if (i==0 && y < base_y + r.ymin)\n            return 0;\n\n        if (y < base_y + r.ymax)\n            break;\n\n        i += r.num_chars;\n        base_y += r.baseline_y_delta;\n    }\n\n    /* below all text, return 'after' last character */\n    if (i >= n)\n        return n;\n\n    /* check if it's before the beginning of the line */\n    if (x < r.x0)\n        return i;\n\n    /* check if it's before the end of the line */\n    if (x < r.x1) {\n        /* search characters in row for one that straddles 'x' */\n        k = i;\n        prev_x = r.x0;\n        for (i=0; i < r.num_chars; ++i) {\n            float w = nk_textedit_get_width(edit, k, i, font);\n            if (x < prev_x+w) {\n                if (x < prev_x+w/2)\n                    return k+i;\n                else return k+i+1;\n            }\n            prev_x += w;\n        }\n        /* shouldn't happen, but if it does, fall through to end-of-line case */\n    }\n\n    /* if the last character is a newline, return that.\n     * otherwise return 'after' the last character */\n    if (nk_str_rune_at(&edit->string, i+r.num_chars-1) == '\\n')\n        return i+r.num_chars-1;\n    else return i+r.num_chars;\n}\nNK_LIB void\nnk_textedit_click(struct nk_text_edit *state, float x, float y,\n    const struct nk_user_font *font, float row_height)\n{\n    /* API click: on mouse down, move the cursor to the clicked location,\n     * and reset the selection */\n    state->cursor = nk_textedit_locate_coord(state, x, y, font, row_height);\n    state->select_start = state->cursor;\n    state->select_end = state->cursor;\n    state->has_preferred_x = 0;\n}\nNK_LIB void\nnk_textedit_drag(struct nk_text_edit *state, float x, float y,\n    const struct nk_user_font *font, float row_height)\n{\n    /* API drag: on mouse drag, move the cursor and selection endpoint\n     * to the clicked location */\n    int p = nk_textedit_locate_coord(state, x, y, font, row_height);\n    if (state->select_start == state->select_end)\n        state->select_start = state->cursor;\n    state->cursor = state->select_end = p;\n}\nNK_INTERN void\nnk_textedit_find_charpos(struct nk_text_find *find, struct nk_text_edit *state,\n    int n, int single_line, const struct nk_user_font *font, float row_height)\n{\n    /* find the x/y location of a character, and remember info about the previous\n     * row in case we get a move-up event (for page up, we'll have to rescan) */\n    struct nk_text_edit_row r;\n    int prev_start = 0;\n    int z = state->string.len;\n    int i=0, first;\n\n    nk_zero_struct(r);\n    if (n == z) {\n        /* if it's at the end, then find the last line -- simpler than trying to\n        explicitly handle this case in the regular code */\n        nk_textedit_layout_row(&r, state, 0, row_height, font);\n        if (single_line) {\n            find->first_char = 0;\n            find->length = z;\n        } else {\n            while (i < z) {\n                prev_start = i;\n                i += r.num_chars;\n                nk_textedit_layout_row(&r, state, i, row_height, font);\n            }\n\n            find->first_char = i;\n            find->length = r.num_chars;\n        }\n        find->x = r.x1;\n        find->y = r.ymin;\n        find->height = r.ymax - r.ymin;\n        find->prev_first = prev_start;\n        return;\n    }\n\n    /* search rows to find the one that straddles character n */\n    find->y = 0;\n\n    for(;;) {\n        nk_textedit_layout_row(&r, state, i, row_height, font);\n        if (n < i + r.num_chars) break;\n        prev_start = i;\n        i += r.num_chars;\n        find->y += r.baseline_y_delta;\n    }\n\n    find->first_char = first = i;\n    find->length = r.num_chars;\n    find->height = r.ymax - r.ymin;\n    find->prev_first = prev_start;\n\n    /* now scan to find xpos */\n    find->x = r.x0;\n    for (i=0; first+i < n; ++i)\n        find->x += nk_textedit_get_width(state, first, i, font);\n}\nNK_INTERN void\nnk_textedit_clamp(struct nk_text_edit *state)\n{\n    /* make the selection/cursor state valid if client altered the string */\n    int n = state->string.len;\n    if (NK_TEXT_HAS_SELECTION(state)) {\n        if (state->select_start > n) state->select_start = n;\n        if (state->select_end   > n) state->select_end = n;\n        /* if clamping forced them to be equal, move the cursor to match */\n        if (state->select_start == state->select_end)\n            state->cursor = state->select_start;\n    }\n    if (state->cursor > n) state->cursor = n;\n}\nNK_API void\nnk_textedit_delete(struct nk_text_edit *state, int where, int len)\n{\n    /* delete characters while updating undo */\n    nk_textedit_makeundo_delete(state, where, len);\n    nk_str_delete_runes(&state->string, where, len);\n    state->has_preferred_x = 0;\n}\nNK_API void\nnk_textedit_delete_selection(struct nk_text_edit *state)\n{\n    /* delete the section */\n    nk_textedit_clamp(state);\n    if (NK_TEXT_HAS_SELECTION(state)) {\n        if (state->select_start < state->select_end) {\n            nk_textedit_delete(state, state->select_start,\n                state->select_end - state->select_start);\n            state->select_end = state->cursor = state->select_start;\n        } else {\n            nk_textedit_delete(state, state->select_end,\n                state->select_start - state->select_end);\n            state->select_start = state->cursor = state->select_end;\n        }\n        state->has_preferred_x = 0;\n    }\n}\nNK_INTERN void\nnk_textedit_sortselection(struct nk_text_edit *state)\n{\n    /* canonicalize the selection so start <= end */\n    if (state->select_end < state->select_start) {\n        int temp = state->select_end;\n        state->select_end = state->select_start;\n        state->select_start = temp;\n    }\n}\nNK_INTERN void\nnk_textedit_move_to_first(struct nk_text_edit *state)\n{\n    /* move cursor to first character of selection */\n    if (NK_TEXT_HAS_SELECTION(state)) {\n        nk_textedit_sortselection(state);\n        state->cursor = state->select_start;\n        state->select_end = state->select_start;\n        state->has_preferred_x = 0;\n    }\n}\nNK_INTERN void\nnk_textedit_move_to_last(struct nk_text_edit *state)\n{\n    /* move cursor to last character of selection */\n    if (NK_TEXT_HAS_SELECTION(state)) {\n        nk_textedit_sortselection(state);\n        nk_textedit_clamp(state);\n        state->cursor = state->select_end;\n        state->select_start = state->select_end;\n        state->has_preferred_x = 0;\n    }\n}\nNK_INTERN int\nnk_is_word_boundary( struct nk_text_edit *state, int idx)\n{\n    int len;\n    nk_rune c;\n    if (idx < 0) return 1;\n    if (!nk_str_at_rune(&state->string, idx, &c, &len)) return 1;\n#ifndef NK_IS_WORD_BOUNDARY\n    return (c == ' ' || c == '\\t' || c == '\\n' || c == '\\r' || c == '\\f' ||\n            c == '\\v' || c == 0x3000);\n#else\n    return NK_IS_WORD_BOUNDARY(c);\n#endif\n}\nNK_INTERN int\nnk_textedit_move_to_word_previous(struct nk_text_edit *state)\n{\n   int c = state->cursor - 1;\n   if (c > 0) {\n      if (nk_is_word_boundary(state, c)) {\n         while (c > 0 && nk_is_word_boundary(state, --c));\n      }\n      while (!nk_is_word_boundary(state, --c));\n      c++;\n   } else {\n      return 0;\n   }\n\n   return c;\n}\nNK_INTERN int\nnk_textedit_move_to_word_next(struct nk_text_edit *state)\n{\n   const int len = state->string.len;\n   int c = state->cursor;\n   if (c < len) {\n      if (!nk_is_word_boundary(state, c)) {\n         while (c < len && !nk_is_word_boundary(state, ++c));\n      }\n      while (c < len && nk_is_word_boundary(state, ++c));\n   } else {\n      return len;\n   }\n\n   return c;\n}\nNK_INTERN void\nnk_textedit_prep_selection_at_cursor(struct nk_text_edit *state)\n{\n    /* update selection and cursor to match each other */\n    if (!NK_TEXT_HAS_SELECTION(state))\n        state->select_start = state->select_end = state->cursor;\n    else state->cursor = state->select_end;\n}\nNK_API nk_bool\nnk_textedit_cut(struct nk_text_edit *state)\n{\n    /* API cut: delete selection */\n    if (state->mode == NK_TEXT_EDIT_MODE_VIEW)\n        return 0;\n    if (NK_TEXT_HAS_SELECTION(state)) {\n        nk_textedit_delete_selection(state); /* implicitly clamps */\n        state->has_preferred_x = 0;\n        return 1;\n    }\n   return 0;\n}\nNK_API nk_bool\nnk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len)\n{\n    /* API paste: replace existing selection with passed-in text */\n    int glyphs;\n    const char *text = (const char *) ctext;\n    if (state->mode == NK_TEXT_EDIT_MODE_VIEW) return 0;\n\n    /* if there's a selection, the paste should delete it */\n    nk_textedit_clamp(state);\n    nk_textedit_delete_selection(state);\n\n    /* try to insert the characters */\n    glyphs = nk_utf_len(ctext, len);\n    if (nk_str_insert_text_char(&state->string, state->cursor, text, len)) {\n        nk_textedit_makeundo_insert(state, state->cursor, glyphs);\n        state->cursor += len;\n        state->has_preferred_x = 0;\n        return 1;\n    }\n    /* remove the undo since we didn't actually insert the characters */\n    if (state->undo.undo_point)\n        --state->undo.undo_point;\n    return 0;\n}\nNK_API void\nnk_textedit_text(struct nk_text_edit *state, const char *text, int total_len)\n{\n    nk_rune unicode;\n    int glyph_len;\n    int text_len = 0;\n\n    NK_ASSERT(state);\n    NK_ASSERT(text);\n    if (!text || !total_len || state->mode == NK_TEXT_EDIT_MODE_VIEW) return;\n\n    glyph_len = nk_utf_decode(text, &unicode, total_len);\n    while ((text_len < total_len) && glyph_len)\n    {\n        /* don't insert a backward delete, just process the event */\n        if (unicode == 127) goto next;\n        /* can't add newline in single-line mode */\n        if (unicode == '\\n' && state->single_line) goto next;\n        /* filter incoming text */\n        if (state->filter && !state->filter(state, unicode)) goto next;\n\n        if (!NK_TEXT_HAS_SELECTION(state) &&\n            state->cursor < state->string.len)\n        {\n            if (state->mode == NK_TEXT_EDIT_MODE_REPLACE) {\n                nk_textedit_makeundo_replace(state, state->cursor, 1, 1);\n                nk_str_delete_runes(&state->string, state->cursor, 1);\n            }\n            if (nk_str_insert_text_utf8(&state->string, state->cursor,\n                                        text+text_len, 1))\n            {\n                ++state->cursor;\n                state->has_preferred_x = 0;\n            }\n        } else {\n            nk_textedit_delete_selection(state); /* implicitly clamps */\n            if (nk_str_insert_text_utf8(&state->string, state->cursor,\n                                        text+text_len, 1))\n            {\n                nk_textedit_makeundo_insert(state, state->cursor, 1);\n                state->cursor = NK_MIN(state->cursor + 1, state->string.len);\n                state->has_preferred_x = 0;\n            }\n        }\n        next:\n        text_len += glyph_len;\n        glyph_len = nk_utf_decode(text + text_len, &unicode, total_len-text_len);\n    }\n}\nNK_LIB void\nnk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod,\n    const struct nk_user_font *font, float row_height)\n{\nretry:\n    switch (key)\n    {\n    case NK_KEY_NONE:\n    case NK_KEY_CTRL:\n    case NK_KEY_ENTER:\n    case NK_KEY_SHIFT:\n    case NK_KEY_TAB:\n    case NK_KEY_COPY:\n    case NK_KEY_CUT:\n    case NK_KEY_PASTE:\n    case NK_KEY_MAX:\n    default: break;\n    case NK_KEY_TEXT_UNDO:\n         nk_textedit_undo(state);\n         state->has_preferred_x = 0;\n         break;\n\n    case NK_KEY_TEXT_REDO:\n        nk_textedit_redo(state);\n        state->has_preferred_x = 0;\n        break;\n\n    case NK_KEY_TEXT_SELECT_ALL:\n        nk_textedit_select_all(state);\n        state->has_preferred_x = 0;\n        break;\n\n    case NK_KEY_TEXT_INSERT_MODE:\n        state->mode = NK_TEXT_EDIT_MODE_INSERT;\n        break;\n    case NK_KEY_TEXT_REPLACE_MODE:\n        state->mode = NK_TEXT_EDIT_MODE_REPLACE;\n        break;\n    case NK_KEY_TEXT_RESET_MODE:\n        state->mode = NK_TEXT_EDIT_MODE_VIEW;\n        break;\n\n    case NK_KEY_LEFT:\n        if (shift_mod) {\n            nk_textedit_clamp(state);\n            nk_textedit_prep_selection_at_cursor(state);\n            /* move selection left */\n            if (state->select_end > 0)\n                --state->select_end;\n            state->cursor = state->select_end;\n            state->has_preferred_x = 0;\n        } else {\n            /* if currently there's a selection,\n             * move cursor to start of selection */\n            if (NK_TEXT_HAS_SELECTION(state))\n                nk_textedit_move_to_first(state);\n            else if (state->cursor > 0)\n               --state->cursor;\n            state->has_preferred_x = 0;\n        } break;\n\n    case NK_KEY_RIGHT:\n        if (shift_mod) {\n            nk_textedit_prep_selection_at_cursor(state);\n            /* move selection right */\n            ++state->select_end;\n            nk_textedit_clamp(state);\n            state->cursor = state->select_end;\n            state->has_preferred_x = 0;\n        } else {\n            /* if currently there's a selection,\n             * move cursor to end of selection */\n            if (NK_TEXT_HAS_SELECTION(state))\n                nk_textedit_move_to_last(state);\n            else ++state->cursor;\n            nk_textedit_clamp(state);\n            state->has_preferred_x = 0;\n        } break;\n\n    case NK_KEY_TEXT_WORD_LEFT:\n        if (shift_mod) {\n            if( !NK_TEXT_HAS_SELECTION( state ) )\n                nk_textedit_prep_selection_at_cursor(state);\n            state->cursor = nk_textedit_move_to_word_previous(state);\n            state->select_end = state->cursor;\n            nk_textedit_clamp(state );\n        } else {\n            if (NK_TEXT_HAS_SELECTION(state))\n                nk_textedit_move_to_first(state);\n            else {\n                state->cursor = nk_textedit_move_to_word_previous(state);\n                nk_textedit_clamp(state );\n            }\n        } break;\n\n    case NK_KEY_TEXT_WORD_RIGHT:\n        if (shift_mod) {\n            if( !NK_TEXT_HAS_SELECTION( state ) )\n                nk_textedit_prep_selection_at_cursor(state);\n            state->cursor = nk_textedit_move_to_word_next(state);\n            state->select_end = state->cursor;\n            nk_textedit_clamp(state);\n        } else {\n            if (NK_TEXT_HAS_SELECTION(state))\n                nk_textedit_move_to_last(state);\n            else {\n                state->cursor = nk_textedit_move_to_word_next(state);\n                nk_textedit_clamp(state );\n            }\n        } break;\n\n    case NK_KEY_DOWN: {\n        struct nk_text_find find;\n        struct nk_text_edit_row row;\n        int i, sel = shift_mod;\n\n        if (state->single_line) {\n            /* on windows, up&down in single-line behave like left&right */\n            key = NK_KEY_RIGHT;\n            goto retry;\n        }\n\n        if (sel)\n            nk_textedit_prep_selection_at_cursor(state);\n        else if (NK_TEXT_HAS_SELECTION(state))\n            nk_textedit_move_to_last(state);\n\n        /* compute current position of cursor point */\n        nk_textedit_clamp(state);\n        nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,\n            font, row_height);\n\n        /* now find character position down a row */\n        if (find.length)\n        {\n            float x;\n            float goal_x = state->has_preferred_x ? state->preferred_x : find.x;\n            int start = find.first_char + find.length;\n\n            state->cursor = start;\n            nk_textedit_layout_row(&row, state, state->cursor, row_height, font);\n            x = row.x0;\n\n            for (i=0; i < row.num_chars && x < row.x1; ++i) {\n                float dx = nk_textedit_get_width(state, start, i, font);\n                x += dx;\n                if (x > goal_x)\n                    break;\n                ++state->cursor;\n            }\n            nk_textedit_clamp(state);\n\n            state->has_preferred_x = 1;\n            state->preferred_x = goal_x;\n            if (sel)\n                state->select_end = state->cursor;\n        }\n    } break;\n\n    case NK_KEY_UP: {\n        struct nk_text_find find;\n        struct nk_text_edit_row row;\n        int i, sel = shift_mod;\n\n        if (state->single_line) {\n            /* on windows, up&down become left&right */\n            key = NK_KEY_LEFT;\n            goto retry;\n        }\n\n        if (sel)\n            nk_textedit_prep_selection_at_cursor(state);\n        else if (NK_TEXT_HAS_SELECTION(state))\n            nk_textedit_move_to_first(state);\n\n         /* compute current position of cursor point */\n         nk_textedit_clamp(state);\n         nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,\n                font, row_height);\n\n         /* can only go up if there's a previous row */\n         if (find.prev_first != find.first_char) {\n            /* now find character position up a row */\n            float x;\n            float goal_x = state->has_preferred_x ? state->preferred_x : find.x;\n\n            state->cursor = find.prev_first;\n            nk_textedit_layout_row(&row, state, state->cursor, row_height, font);\n            x = row.x0;\n\n            for (i=0; i < row.num_chars && x < row.x1; ++i) {\n                float dx = nk_textedit_get_width(state, find.prev_first, i, font);\n                x += dx;\n                if (x > goal_x)\n                    break;\n                ++state->cursor;\n            }\n            nk_textedit_clamp(state);\n\n            state->has_preferred_x = 1;\n            state->preferred_x = goal_x;\n            if (sel) state->select_end = state->cursor;\n         }\n      } break;\n\n    case NK_KEY_DEL:\n        if (state->mode == NK_TEXT_EDIT_MODE_VIEW)\n            break;\n        if (NK_TEXT_HAS_SELECTION(state))\n            nk_textedit_delete_selection(state);\n        else {\n            int n = state->string.len;\n            if (state->cursor < n)\n                nk_textedit_delete(state, state->cursor, 1);\n         }\n         state->has_preferred_x = 0;\n         break;\n\n    case NK_KEY_BACKSPACE:\n        if (state->mode == NK_TEXT_EDIT_MODE_VIEW)\n            break;\n        if (NK_TEXT_HAS_SELECTION(state))\n            nk_textedit_delete_selection(state);\n        else {\n            nk_textedit_clamp(state);\n            if (state->cursor > 0) {\n                nk_textedit_delete(state, state->cursor-1, 1);\n                --state->cursor;\n            }\n         }\n         state->has_preferred_x = 0;\n         break;\n\n    case NK_KEY_TEXT_START:\n         if (shift_mod) {\n            nk_textedit_prep_selection_at_cursor(state);\n            state->cursor = state->select_end = 0;\n            state->has_preferred_x = 0;\n         } else {\n            state->cursor = state->select_start = state->select_end = 0;\n            state->has_preferred_x = 0;\n         }\n         break;\n\n    case NK_KEY_TEXT_END:\n         if (shift_mod) {\n            nk_textedit_prep_selection_at_cursor(state);\n            state->cursor = state->select_end = state->string.len;\n            state->has_preferred_x = 0;\n         } else {\n            state->cursor = state->string.len;\n            state->select_start = state->select_end = 0;\n            state->has_preferred_x = 0;\n         }\n         break;\n\n    case NK_KEY_TEXT_LINE_START: {\n        if (shift_mod) {\n            struct nk_text_find find;\n           nk_textedit_clamp(state);\n            nk_textedit_prep_selection_at_cursor(state);\n            if (state->string.len && state->cursor == state->string.len)\n                --state->cursor;\n            nk_textedit_find_charpos(&find, state,state->cursor, state->single_line,\n                font, row_height);\n            state->cursor = state->select_end = find.first_char;\n            state->has_preferred_x = 0;\n        } else {\n            struct nk_text_find find;\n            if (state->string.len && state->cursor == state->string.len)\n                --state->cursor;\n            nk_textedit_clamp(state);\n            nk_textedit_move_to_first(state);\n            nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,\n                font, row_height);\n            state->cursor = find.first_char;\n            state->has_preferred_x = 0;\n        }\n      } break;\n\n    case NK_KEY_TEXT_LINE_END: {\n        if (shift_mod) {\n            struct nk_text_find find;\n            nk_textedit_clamp(state);\n            nk_textedit_prep_selection_at_cursor(state);\n            nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,\n                font, row_height);\n            state->has_preferred_x = 0;\n            state->cursor = find.first_char + find.length;\n            if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\\n')\n                --state->cursor;\n            state->select_end = state->cursor;\n        } else {\n            struct nk_text_find find;\n            nk_textedit_clamp(state);\n            nk_textedit_move_to_first(state);\n            nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,\n                font, row_height);\n\n            state->has_preferred_x = 0;\n            state->cursor = find.first_char + find.length;\n            if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\\n')\n                --state->cursor;\n        }} break;\n    }\n}\nNK_INTERN void\nnk_textedit_flush_redo(struct nk_text_undo_state *state)\n{\n    state->redo_point = NK_TEXTEDIT_UNDOSTATECOUNT;\n    state->redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT;\n}\nNK_INTERN void\nnk_textedit_discard_undo(struct nk_text_undo_state *state)\n{\n    /* discard the oldest entry in the undo list */\n    if (state->undo_point > 0) {\n        /* if the 0th undo state has characters, clean those up */\n        if (state->undo_rec[0].char_storage >= 0) {\n            int n = state->undo_rec[0].insert_length, i;\n            /* delete n characters from all other records */\n            state->undo_char_point = (short)(state->undo_char_point - n);\n            NK_MEMCPY(state->undo_char, state->undo_char + n,\n                (nk_size)state->undo_char_point*sizeof(nk_rune));\n            for (i=0; i < state->undo_point; ++i) {\n                if (state->undo_rec[i].char_storage >= 0)\n                state->undo_rec[i].char_storage = (short)\n                    (state->undo_rec[i].char_storage - n);\n            }\n        }\n        --state->undo_point;\n        NK_MEMCPY(state->undo_rec, state->undo_rec+1,\n            (nk_size)((nk_size)state->undo_point * sizeof(state->undo_rec[0])));\n    }\n}\nNK_INTERN void\nnk_textedit_discard_redo(struct nk_text_undo_state *state)\n{\n/*  discard the oldest entry in the redo list--it's bad if this\n    ever happens, but because undo & redo have to store the actual\n    characters in different cases, the redo character buffer can\n    fill up even though the undo buffer didn't */\n    nk_size num;\n    int k = NK_TEXTEDIT_UNDOSTATECOUNT-1;\n    if (state->redo_point <= k) {\n        /* if the k'th undo state has characters, clean those up */\n        if (state->undo_rec[k].char_storage >= 0) {\n            int n = state->undo_rec[k].insert_length, i;\n            /* delete n characters from all other records */\n            state->redo_char_point = (short)(state->redo_char_point + n);\n            num = (nk_size)(NK_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point);\n            NK_MEMCPY(state->undo_char + state->redo_char_point,\n                state->undo_char + state->redo_char_point-n, num * sizeof(char));\n            for (i = state->redo_point; i < k; ++i) {\n                if (state->undo_rec[i].char_storage >= 0) {\n                    state->undo_rec[i].char_storage = (short)\n                        (state->undo_rec[i].char_storage + n);\n                }\n            }\n        }\n        ++state->redo_point;\n        num = (nk_size)(NK_TEXTEDIT_UNDOSTATECOUNT - state->redo_point);\n        if (num) NK_MEMCPY(state->undo_rec + state->redo_point-1,\n            state->undo_rec + state->redo_point, num * sizeof(state->undo_rec[0]));\n    }\n}\nNK_INTERN struct nk_text_undo_record*\nnk_textedit_create_undo_record(struct nk_text_undo_state *state, int numchars)\n{\n    /* any time we create a new undo record, we discard redo*/\n    nk_textedit_flush_redo(state);\n\n    /* if we have no free records, we have to make room,\n     * by sliding the existing records down */\n    if (state->undo_point == NK_TEXTEDIT_UNDOSTATECOUNT)\n        nk_textedit_discard_undo(state);\n\n    /* if the characters to store won't possibly fit in the buffer,\n     * we can't undo */\n    if (numchars > NK_TEXTEDIT_UNDOCHARCOUNT) {\n        state->undo_point = 0;\n        state->undo_char_point = 0;\n        return 0;\n    }\n\n    /* if we don't have enough free characters in the buffer,\n     * we have to make room */\n    while (state->undo_char_point + numchars > NK_TEXTEDIT_UNDOCHARCOUNT)\n        nk_textedit_discard_undo(state);\n    return &state->undo_rec[state->undo_point++];\n}\nNK_INTERN nk_rune*\nnk_textedit_createundo(struct nk_text_undo_state *state, int pos,\n    int insert_len, int delete_len)\n{\n    struct nk_text_undo_record *r = nk_textedit_create_undo_record(state, insert_len);\n    if (r == 0)\n        return 0;\n\n    r->where = pos;\n    r->insert_length = (short) insert_len;\n    r->delete_length = (short) delete_len;\n\n    if (insert_len == 0) {\n        r->char_storage = -1;\n        return 0;\n    } else {\n        r->char_storage = state->undo_char_point;\n        state->undo_char_point = (short)(state->undo_char_point +  insert_len);\n        return &state->undo_char[r->char_storage];\n    }\n}\nNK_API void\nnk_textedit_undo(struct nk_text_edit *state)\n{\n    struct nk_text_undo_state *s = &state->undo;\n    struct nk_text_undo_record u, *r;\n    if (s->undo_point == 0)\n        return;\n\n    /* we need to do two things: apply the undo record, and create a redo record */\n    u = s->undo_rec[s->undo_point-1];\n    r = &s->undo_rec[s->redo_point-1];\n    r->char_storage = -1;\n\n    r->insert_length = u.delete_length;\n    r->delete_length = u.insert_length;\n    r->where = u.where;\n\n    if (u.delete_length)\n    {\n       /*   if the undo record says to delete characters, then the redo record will\n            need to re-insert the characters that get deleted, so we need to store\n            them.\n            there are three cases:\n                - there's enough room to store the characters\n                - characters stored for *redoing* don't leave room for redo\n                - characters stored for *undoing* don't leave room for redo\n            if the last is true, we have to bail */\n        if (s->undo_char_point + u.delete_length >= NK_TEXTEDIT_UNDOCHARCOUNT) {\n            /* the undo records take up too much character space; there's no space\n            * to store the redo characters */\n            r->insert_length = 0;\n        } else {\n            int i;\n            /* there's definitely room to store the characters eventually */\n            while (s->undo_char_point + u.delete_length > s->redo_char_point) {\n                /* there's currently not enough room, so discard a redo record */\n                nk_textedit_discard_redo(s);\n                /* should never happen: */\n                if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT)\n                    return;\n            }\n\n            r = &s->undo_rec[s->redo_point-1];\n            r->char_storage = (short)(s->redo_char_point - u.delete_length);\n            s->redo_char_point = (short)(s->redo_char_point -  u.delete_length);\n\n            /* now save the characters */\n            for (i=0; i < u.delete_length; ++i)\n                s->undo_char[r->char_storage + i] =\n                    nk_str_rune_at(&state->string, u.where + i);\n        }\n        /* now we can carry out the deletion */\n        nk_str_delete_runes(&state->string, u.where, u.delete_length);\n    }\n\n    /* check type of recorded action: */\n    if (u.insert_length) {\n        /* easy case: was a deletion, so we need to insert n characters */\n        nk_str_insert_text_runes(&state->string, u.where,\n            &s->undo_char[u.char_storage], u.insert_length);\n        s->undo_char_point = (short)(s->undo_char_point - u.insert_length);\n    }\n    state->cursor = (short)(u.where + u.insert_length);\n\n    s->undo_point--;\n    s->redo_point--;\n}\nNK_API void\nnk_textedit_redo(struct nk_text_edit *state)\n{\n    struct nk_text_undo_state *s = &state->undo;\n    struct nk_text_undo_record *u, r;\n    if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT)\n        return;\n\n    /* we need to do two things: apply the redo record, and create an undo record */\n    u = &s->undo_rec[s->undo_point];\n    r = s->undo_rec[s->redo_point];\n\n    /* we KNOW there must be room for the undo record, because the redo record\n    was derived from an undo record */\n    u->delete_length = r.insert_length;\n    u->insert_length = r.delete_length;\n    u->where = r.where;\n    u->char_storage = -1;\n\n    if (r.delete_length) {\n        /* the redo record requires us to delete characters, so the undo record\n        needs to store the characters */\n        if (s->undo_char_point + u->insert_length > s->redo_char_point) {\n            u->insert_length = 0;\n            u->delete_length = 0;\n        } else {\n            int i;\n            u->char_storage = s->undo_char_point;\n            s->undo_char_point = (short)(s->undo_char_point + u->insert_length);\n\n            /* now save the characters */\n            for (i=0; i < u->insert_length; ++i) {\n                s->undo_char[u->char_storage + i] =\n                    nk_str_rune_at(&state->string, u->where + i);\n            }\n        }\n        nk_str_delete_runes(&state->string, r.where, r.delete_length);\n    }\n\n    if (r.insert_length) {\n        /* easy case: need to insert n characters */\n        nk_str_insert_text_runes(&state->string, r.where,\n            &s->undo_char[r.char_storage], r.insert_length);\n    }\n    state->cursor = r.where + r.insert_length;\n\n    s->undo_point++;\n    s->redo_point++;\n}\nNK_INTERN void\nnk_textedit_makeundo_insert(struct nk_text_edit *state, int where, int length)\n{\n    nk_textedit_createundo(&state->undo, where, 0, length);\n}\nNK_INTERN void\nnk_textedit_makeundo_delete(struct nk_text_edit *state, int where, int length)\n{\n    int i;\n    nk_rune *p = nk_textedit_createundo(&state->undo, where, length, 0);\n    if (p) {\n        for (i=0; i < length; ++i)\n            p[i] = nk_str_rune_at(&state->string, where+i);\n    }\n}\nNK_INTERN void\nnk_textedit_makeundo_replace(struct nk_text_edit *state, int where,\n    int old_length, int new_length)\n{\n    int i;\n    nk_rune *p = nk_textedit_createundo(&state->undo, where, old_length, new_length);\n    if (p) {\n        for (i=0; i < old_length; ++i)\n            p[i] = nk_str_rune_at(&state->string, where+i);\n    }\n}\nNK_LIB void\nnk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type,\n    nk_plugin_filter filter)\n{\n    /* reset the state to default */\n   state->undo.undo_point = 0;\n   state->undo.undo_char_point = 0;\n   state->undo.redo_point = NK_TEXTEDIT_UNDOSTATECOUNT;\n   state->undo.redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT;\n   state->select_end = state->select_start = 0;\n   state->cursor = 0;\n   state->has_preferred_x = 0;\n   state->preferred_x = 0;\n   state->cursor_at_end_of_line = 0;\n   state->initialized = 1;\n   state->single_line = (unsigned char)(type == NK_TEXT_EDIT_SINGLE_LINE);\n   state->mode = NK_TEXT_EDIT_MODE_VIEW;\n   state->filter = filter;\n   state->scrollbar = nk_vec2(0,0);\n}\nNK_API void\nnk_textedit_init_fixed(struct nk_text_edit *state, void *memory, nk_size size)\n{\n    NK_ASSERT(state);\n    NK_ASSERT(memory);\n    if (!state || !memory || !size) return;\n    NK_MEMSET(state, 0, sizeof(struct nk_text_edit));\n    nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);\n    nk_str_init_fixed(&state->string, memory, size);\n}\nNK_API void\nnk_textedit_init(struct nk_text_edit *state, const struct nk_allocator *alloc, nk_size size)\n{\n    NK_ASSERT(state);\n    NK_ASSERT(alloc);\n    if (!state || !alloc) return;\n    NK_MEMSET(state, 0, sizeof(struct nk_text_edit));\n    nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);\n    nk_str_init(&state->string, alloc, size);\n}\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void\nnk_textedit_init_default(struct nk_text_edit *state)\n{\n    NK_ASSERT(state);\n    if (!state) return;\n    NK_MEMSET(state, 0, sizeof(struct nk_text_edit));\n    nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);\n    nk_str_init_default(&state->string);\n}\n#endif\nNK_API void\nnk_textedit_select_all(struct nk_text_edit *state)\n{\n    NK_ASSERT(state);\n    state->select_start = 0;\n    state->select_end = state->string.len;\n}\nNK_API void\nnk_textedit_free(struct nk_text_edit *state)\n{\n    NK_ASSERT(state);\n    if (!state) return;\n    nk_str_free(&state->string);\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                          FILTER\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_filter_default(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(unicode);\n    NK_UNUSED(box);\n    return nk_true;\n}\nNK_API nk_bool\nnk_filter_ascii(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(box);\n    if (unicode > 128) return nk_false;\n    else return nk_true;\n}\nNK_API nk_bool\nnk_filter_float(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(box);\n    if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-')\n        return nk_false;\n    else return nk_true;\n}\nNK_API nk_bool\nnk_filter_decimal(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(box);\n    if ((unicode < '0' || unicode > '9') && unicode != '-')\n        return nk_false;\n    else return nk_true;\n}\nNK_API nk_bool\nnk_filter_hex(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(box);\n    if ((unicode < '0' || unicode > '9') &&\n        (unicode < 'a' || unicode > 'f') &&\n        (unicode < 'A' || unicode > 'F'))\n        return nk_false;\n    else return nk_true;\n}\nNK_API nk_bool\nnk_filter_oct(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(box);\n    if (unicode < '0' || unicode > '7')\n        return nk_false;\n    else return nk_true;\n}\nNK_API nk_bool\nnk_filter_binary(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(box);\n    if (unicode != '0' && unicode != '1')\n        return nk_false;\n    else return nk_true;\n}\n\n/* ===============================================================\n *\n *                          EDIT\n *\n * ===============================================================*/\nNK_LIB void\nnk_edit_draw_text(struct nk_command_buffer *out,\n    const struct nk_style_edit *style, float pos_x, float pos_y,\n    float x_offset, const char *text, int byte_len, float row_height,\n    const struct nk_user_font *font, struct nk_color background,\n    struct nk_color foreground, nk_bool is_selected)\n{\n    NK_ASSERT(out);\n    NK_ASSERT(font);\n    NK_ASSERT(style);\n    if (!text || !byte_len || !out || !style) return;\n\n    {int glyph_len = 0;\n    nk_rune unicode = 0;\n    int text_len = 0;\n    float line_width = 0;\n    float glyph_width;\n    const char *line = text;\n    float line_offset = 0;\n    int line_count = 0;\n\n    struct nk_text txt;\n    txt.padding = nk_vec2(0,0);\n    txt.background = background;\n    txt.text = foreground;\n\n    foreground = nk_rgb_factor(foreground, style->color_factor);\n    background = nk_rgb_factor(background, style->color_factor);\n\n    glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len);\n    if (!glyph_len) return;\n    while ((text_len < byte_len) && glyph_len)\n    {\n        if (unicode == '\\n') {\n            /* new line separator so draw previous line */\n            struct nk_rect label;\n            label.y = pos_y + line_offset;\n            label.h = row_height;\n            label.w = line_width;\n            label.x = pos_x;\n            if (!line_count)\n                label.x += x_offset;\n\n            if (is_selected) /* selection needs to draw different background color */\n                nk_fill_rect(out, label, 0, background);\n            nk_widget_text(out, label, line, (int)((text + text_len) - line),\n                &txt, NK_TEXT_CENTERED, font);\n\n            text_len++;\n            line_count++;\n            line_width = 0;\n            line = text + text_len;\n            line_offset += row_height;\n            glyph_len = nk_utf_decode(text + text_len, &unicode, (int)(byte_len-text_len));\n            continue;\n        }\n        if (unicode == '\\r') {\n            text_len++;\n            glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);\n            continue;\n        }\n        glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);\n        line_width += (float)glyph_width;\n        text_len += glyph_len;\n        glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);\n        continue;\n    }\n    if (line_width > 0) {\n        /* draw last line */\n        struct nk_rect label;\n        label.y = pos_y + line_offset;\n        label.h = row_height;\n        label.w = line_width;\n        label.x = pos_x;\n        if (!line_count)\n            label.x += x_offset;\n\n        if (is_selected)\n            nk_fill_rect(out, label, 0, background);\n        nk_widget_text(out, label, line, (int)((text + text_len) - line),\n            &txt, NK_TEXT_LEFT, font);\n    }}\n}\nNK_LIB nk_flags\nnk_do_edit(nk_flags *state, struct nk_command_buffer *out,\n    struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter,\n    struct nk_text_edit *edit, const struct nk_style_edit *style,\n    struct nk_input *in, const struct nk_user_font *font)\n{\n    struct nk_rect area;\n    nk_flags ret = 0;\n    float row_height;\n    char prev_state = 0;\n    char is_hovered = 0;\n    char select_all = 0;\n    char cursor_follow = 0;\n    struct nk_rect old_clip;\n    struct nk_rect clip;\n\n    NK_ASSERT(state);\n    NK_ASSERT(out);\n    NK_ASSERT(style);\n    if (!state || !out || !style)\n        return ret;\n\n    /* visible text area calculation */\n    area.x = bounds.x + style->padding.x + style->border;\n    area.y = bounds.y + style->padding.y + style->border;\n    area.w = bounds.w - (2.0f * style->padding.x + 2 * style->border);\n    area.h = bounds.h - (2.0f * style->padding.y + 2 * style->border);\n    if (flags & NK_EDIT_MULTILINE)\n        area.w = NK_MAX(0, area.w - style->scrollbar_size.x);\n    row_height = (flags & NK_EDIT_MULTILINE)? font->height + style->row_padding: area.h;\n\n    /* calculate clipping rectangle */\n    old_clip = out->clip;\n    nk_unify(&clip, &old_clip, area.x, area.y, area.x + area.w, area.y + area.h);\n\n    /* update edit state */\n    prev_state = (char)edit->active;\n    if (in && in->mouse.buttons[NK_BUTTON_LEFT].clicked && in->mouse.buttons[NK_BUTTON_LEFT].down) {\n        edit->active = NK_INBOX(in->mouse.pos.x, in->mouse.pos.y,\n                                bounds.x, bounds.y, bounds.w, bounds.h);\n    }\n\n    /* (de)activate text editor */\n    if (!prev_state && edit->active) {\n        const enum nk_text_edit_type type = (flags & NK_EDIT_MULTILINE) ?\n            NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE;\n        /* keep scroll position when re-activating edit widget */\n        struct nk_vec2 oldscrollbar = edit->scrollbar;\n        nk_textedit_clear_state(edit, type, filter);\n        edit->scrollbar = oldscrollbar;\n        if (flags & NK_EDIT_AUTO_SELECT)\n            select_all = nk_true;\n        if (flags & NK_EDIT_GOTO_END_ON_ACTIVATE) {\n            edit->cursor = edit->string.len;\n            in = 0;\n        }\n    } else if (!edit->active) edit->mode = NK_TEXT_EDIT_MODE_VIEW;\n    if (flags & NK_EDIT_READ_ONLY)\n        edit->mode = NK_TEXT_EDIT_MODE_VIEW;\n    else if (flags & NK_EDIT_ALWAYS_INSERT_MODE)\n        edit->mode = NK_TEXT_EDIT_MODE_INSERT;\n\n    ret = (edit->active) ? NK_EDIT_ACTIVE: NK_EDIT_INACTIVE;\n    if (prev_state != edit->active)\n        ret |= (edit->active) ? NK_EDIT_ACTIVATED: NK_EDIT_DEACTIVATED;\n\n    /* handle user input */\n    if (edit->active && in)\n    {\n        int shift_mod = in->keyboard.keys[NK_KEY_SHIFT].down;\n        const float mouse_x = (in->mouse.pos.x - area.x) + edit->scrollbar.x;\n        const float mouse_y = (in->mouse.pos.y - area.y) + edit->scrollbar.y;\n\n        /* mouse click handler */\n        is_hovered = (char)nk_input_is_mouse_hovering_rect(in, area);\n        if (select_all) {\n            nk_textedit_select_all(edit);\n        } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked) {\n            nk_textedit_click(edit, mouse_x, mouse_y, font, row_height);\n        } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&\n            nk_input_is_mouse_moved(in)) {\n            nk_textedit_drag(edit, mouse_x, mouse_y, font, row_height);\n            cursor_follow = nk_true;\n        } else if (is_hovered && in->mouse.buttons[NK_BUTTON_RIGHT].clicked &&\n            in->mouse.buttons[NK_BUTTON_RIGHT].down) {\n            nk_textedit_key(edit, NK_KEY_TEXT_WORD_LEFT, nk_false, font, row_height);\n            nk_textedit_key(edit, NK_KEY_TEXT_WORD_RIGHT, nk_true, font, row_height);\n            cursor_follow = nk_true;\n        }\n\n        {int i; /* keyboard input */\n        int old_mode = edit->mode;\n        for (i = 0; i < NK_KEY_MAX; ++i) {\n            if (i == NK_KEY_ENTER || i == NK_KEY_TAB) continue; /* special case */\n            if (nk_input_is_key_pressed(in, (enum nk_keys)i)) {\n                nk_textedit_key(edit, (enum nk_keys)i, shift_mod, font, row_height);\n                cursor_follow = nk_true;\n            }\n        }\n        if (old_mode != edit->mode) {\n            in->keyboard.text_len = 0;\n        }}\n\n        /* text input */\n        edit->filter = filter;\n        if (in->keyboard.text_len) {\n            nk_textedit_text(edit, in->keyboard.text, in->keyboard.text_len);\n            cursor_follow = nk_true;\n            in->keyboard.text_len = 0;\n        }\n\n        /* enter key handler */\n        if (nk_input_is_key_pressed(in, NK_KEY_ENTER)) {\n            cursor_follow = nk_true;\n            if (flags & NK_EDIT_CTRL_ENTER_NEWLINE && shift_mod)\n                nk_textedit_text(edit, \"\\n\", 1);\n            else if (flags & NK_EDIT_SIG_ENTER)\n                ret |= NK_EDIT_COMMITED;\n            else nk_textedit_text(edit, \"\\n\", 1);\n        }\n\n        /* cut & copy handler */\n        {int copy= nk_input_is_key_pressed(in, NK_KEY_COPY);\n        int cut = nk_input_is_key_pressed(in, NK_KEY_CUT);\n        if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD))\n        {\n            int glyph_len;\n            nk_rune unicode;\n            const char *text;\n            int b = edit->select_start;\n            int e = edit->select_end;\n\n            int begin = NK_MIN(b, e);\n            int end = NK_MAX(b, e);\n            text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len);\n            if (edit->clip.copy)\n                edit->clip.copy(edit->clip.userdata, text, end - begin);\n            if (cut && !(flags & NK_EDIT_READ_ONLY)){\n                nk_textedit_cut(edit);\n                cursor_follow = nk_true;\n            }\n        }}\n\n        /* paste handler */\n        {int paste = nk_input_is_key_pressed(in, NK_KEY_PASTE);\n        if (paste && (flags & NK_EDIT_CLIPBOARD) && edit->clip.paste) {\n            edit->clip.paste(edit->clip.userdata, edit);\n            cursor_follow = nk_true;\n        }}\n\n        /* tab handler */\n        {int tab = nk_input_is_key_pressed(in, NK_KEY_TAB);\n        if (tab && (flags & NK_EDIT_ALLOW_TAB)) {\n            nk_textedit_text(edit, \"    \", 4);\n            cursor_follow = nk_true;\n        }}\n    }\n\n    /* set widget state */\n    if (edit->active)\n        *state = NK_WIDGET_STATE_ACTIVE;\n    else nk_widget_state_reset(state);\n\n    if (is_hovered)\n        *state |= NK_WIDGET_STATE_HOVERED;\n\n    /* DRAW EDIT */\n    {const char *text = nk_str_get_const(&edit->string);\n    int len = nk_str_len_char(&edit->string);\n\n    {/* select background colors/images  */\n    const struct nk_style_item *background;\n    if (*state & NK_WIDGET_STATE_ACTIVED)\n        background = &style->active;\n    else if (*state & NK_WIDGET_STATE_HOVER)\n        background = &style->hover;\n    else background = &style->normal;\n\n    /* draw background frame */\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));\n            nk_stroke_rect(out, bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));\n            break;\n    }}\n\n\n    area.w = NK_MAX(0, area.w - style->cursor_size);\n    if (edit->active)\n    {\n        int total_lines = 1;\n        struct nk_vec2 text_size = nk_vec2(0,0);\n\n        /* text pointer positions */\n        const char *cursor_ptr = 0;\n        const char *select_begin_ptr = 0;\n        const char *select_end_ptr = 0;\n\n        /* 2D pixel positions */\n        struct nk_vec2 cursor_pos = nk_vec2(0,0);\n        struct nk_vec2 selection_offset_start = nk_vec2(0,0);\n        struct nk_vec2 selection_offset_end = nk_vec2(0,0);\n\n        int selection_begin = NK_MIN(edit->select_start, edit->select_end);\n        int selection_end = NK_MAX(edit->select_start, edit->select_end);\n\n        /* calculate total line count + total space + cursor/selection position */\n        float line_width = 0.0f;\n        if (text && len)\n        {\n            /* utf8 encoding */\n            float glyph_width;\n            int glyph_len = 0;\n            nk_rune unicode = 0;\n            int text_len = 0;\n            int glyphs = 0;\n            int row_begin = 0;\n\n            glyph_len = nk_utf_decode(text, &unicode, len);\n            glyph_width = font->width(font->userdata, font->height, text, glyph_len);\n            line_width = 0;\n\n            /* iterate all lines */\n            while ((text_len < len) && glyph_len)\n            {\n                /* set cursor 2D position and line */\n                if (!cursor_ptr && glyphs == edit->cursor)\n                {\n                    int glyph_offset;\n                    struct nk_vec2 out_offset;\n                    struct nk_vec2 row_size;\n                    const char *remaining;\n\n                    /* calculate 2d position */\n                    cursor_pos.y = (float)(total_lines-1) * row_height;\n                    row_size = nk_text_calculate_text_bounds(font, text+row_begin,\n                                text_len-row_begin, row_height, &remaining,\n                                &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);\n                    cursor_pos.x = row_size.x;\n                    cursor_ptr = text + text_len;\n                }\n\n                /* set start selection 2D position and line */\n                if (!select_begin_ptr && edit->select_start != edit->select_end &&\n                    glyphs == selection_begin)\n                {\n                    int glyph_offset;\n                    struct nk_vec2 out_offset;\n                    struct nk_vec2 row_size;\n                    const char *remaining;\n\n                    /* calculate 2d position */\n                    selection_offset_start.y = (float)(NK_MAX(total_lines-1,0)) * row_height;\n                    row_size = nk_text_calculate_text_bounds(font, text+row_begin,\n                                text_len-row_begin, row_height, &remaining,\n                                &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);\n                    selection_offset_start.x = row_size.x;\n                    select_begin_ptr = text + text_len;\n                }\n\n                /* set end selection 2D position and line */\n                if (!select_end_ptr && edit->select_start != edit->select_end &&\n                    glyphs == selection_end)\n                {\n                    int glyph_offset;\n                    struct nk_vec2 out_offset;\n                    struct nk_vec2 row_size;\n                    const char *remaining;\n\n                    /* calculate 2d position */\n                    selection_offset_end.y = (float)(total_lines-1) * row_height;\n                    row_size = nk_text_calculate_text_bounds(font, text+row_begin,\n                                text_len-row_begin, row_height, &remaining,\n                                &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);\n                    selection_offset_end.x = row_size.x;\n                    select_end_ptr = text + text_len;\n                }\n                if (unicode == '\\n') {\n                    text_size.x = NK_MAX(text_size.x, line_width);\n                    total_lines++;\n                    line_width = 0;\n                    text_len++;\n                    glyphs++;\n                    row_begin = text_len;\n                    glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);\n                    glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);\n                    continue;\n                }\n\n                glyphs++;\n                text_len += glyph_len;\n                line_width += (float)glyph_width;\n\n                glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);\n                glyph_width = font->width(font->userdata, font->height,\n                    text+text_len, glyph_len);\n                continue;\n            }\n            text_size.y = (float)total_lines * row_height;\n\n            /* handle case when cursor is at end of text buffer */\n            if (!cursor_ptr && edit->cursor == edit->string.len) {\n                cursor_pos.x = line_width;\n                cursor_pos.y = text_size.y - row_height;\n            }\n        }\n        {\n            /* scrollbar */\n            if (cursor_follow)\n            {\n                /* update scrollbar to follow cursor */\n                if (!(flags & NK_EDIT_NO_HORIZONTAL_SCROLL)) {\n                    /* horizontal scroll */\n                    const float scroll_increment = area.w * 0.25f;\n                    if (cursor_pos.x < edit->scrollbar.x)\n                        edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - scroll_increment);\n                    if (cursor_pos.x >= edit->scrollbar.x + area.w)\n                        edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - area.w + scroll_increment);\n                } else edit->scrollbar.x = 0;\n\n                if (flags & NK_EDIT_MULTILINE) {\n                    /* vertical scroll: like horizontal, it only adjusts if the\n                     * cursor leaves the visible area, and then only just enough\n                     * to keep it visible */\n                    if (cursor_pos.y < edit->scrollbar.y)\n                        edit->scrollbar.y = NK_MAX(0.0f, cursor_pos.y);\n                    if (cursor_pos.y > edit->scrollbar.y + area.h - row_height)\n                        edit->scrollbar.y = edit->scrollbar.y + row_height;\n                } else edit->scrollbar.y = 0;\n            }\n\n            /* scrollbar widget */\n            if (flags & NK_EDIT_MULTILINE)\n            {\n                nk_flags ws;\n                struct nk_rect scroll;\n                float scroll_target;\n                float scroll_offset;\n                float scroll_step;\n                float scroll_inc;\n\n                scroll = area;\n                scroll.x = (bounds.x + bounds.w - style->border) - style->scrollbar_size.x;\n                scroll.w = style->scrollbar_size.x;\n\n                scroll_offset = edit->scrollbar.y;\n                scroll_step = scroll.h * 0.10f;\n                scroll_inc = scroll.h * 0.01f;\n                scroll_target = text_size.y;\n                edit->scrollbar.y = nk_do_scrollbarv(&ws, out, scroll, is_hovered,\n                        scroll_offset, scroll_target, scroll_step, scroll_inc,\n                        &style->scrollbar, in, font);\n                /* Eat mouse scroll if we're active */\n                if (is_hovered && in->mouse.scroll_delta.y) {\n                    in->mouse.scroll_delta.y = 0;\n                }\n            }\n        }\n\n        /* draw text */\n        {struct nk_color background_color;\n        struct nk_color text_color;\n        struct nk_color sel_background_color;\n        struct nk_color sel_text_color;\n        struct nk_color cursor_color;\n        struct nk_color cursor_text_color;\n        const struct nk_style_item *background;\n        nk_push_scissor(out, clip);\n\n        /* select correct colors to draw */\n        if (*state & NK_WIDGET_STATE_ACTIVED) {\n            background = &style->active;\n            text_color = style->text_active;\n            sel_text_color = style->selected_text_hover;\n            sel_background_color = style->selected_hover;\n            cursor_color = style->cursor_hover;\n            cursor_text_color = style->cursor_text_hover;\n        } else if (*state & NK_WIDGET_STATE_HOVER) {\n            background = &style->hover;\n            text_color = style->text_hover;\n            sel_text_color = style->selected_text_hover;\n            sel_background_color = style->selected_hover;\n            cursor_text_color = style->cursor_text_hover;\n            cursor_color = style->cursor_hover;\n        } else {\n            background = &style->normal;\n            text_color = style->text_normal;\n            sel_text_color = style->selected_text_normal;\n            sel_background_color = style->selected_normal;\n            cursor_color = style->cursor_normal;\n            cursor_text_color = style->cursor_text_normal;\n        }\n        if (background->type == NK_STYLE_ITEM_IMAGE)\n            background_color = nk_rgba(0,0,0,0);\n        else\n            background_color = background->data.color;\n\n        cursor_color = nk_rgb_factor(cursor_color, style->color_factor);\n        cursor_text_color = nk_rgb_factor(cursor_text_color, style->color_factor);\n\n        if (edit->select_start == edit->select_end) {\n            /* no selection so just draw the complete text */\n            const char *begin = nk_str_get_const(&edit->string);\n            int l = nk_str_len_char(&edit->string);\n            nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,\n                area.y - edit->scrollbar.y, 0, begin, l, row_height, font,\n                background_color, text_color, nk_false);\n        } else {\n            /* edit has selection so draw 1-3 text chunks */\n            if (edit->select_start != edit->select_end && selection_begin > 0){\n                /* draw unselected text before selection */\n                const char *begin = nk_str_get_const(&edit->string);\n                NK_ASSERT(select_begin_ptr);\n                nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,\n                    area.y - edit->scrollbar.y, 0, begin, (int)(select_begin_ptr - begin),\n                    row_height, font, background_color, text_color, nk_false);\n            }\n            if (edit->select_start != edit->select_end) {\n                /* draw selected text */\n                NK_ASSERT(select_begin_ptr);\n                if (!select_end_ptr) {\n                    const char *begin = nk_str_get_const(&edit->string);\n                    select_end_ptr = begin + nk_str_len_char(&edit->string);\n                }\n                nk_edit_draw_text(out, style,\n                    area.x - edit->scrollbar.x,\n                    area.y + selection_offset_start.y - edit->scrollbar.y,\n                    selection_offset_start.x,\n                    select_begin_ptr, (int)(select_end_ptr - select_begin_ptr),\n                    row_height, font, sel_background_color, sel_text_color, nk_true);\n            }\n            if ((edit->select_start != edit->select_end &&\n                selection_end < edit->string.len))\n            {\n                /* draw unselected text after selected text */\n                const char *begin = select_end_ptr;\n                const char *end = nk_str_get_const(&edit->string) +\n                                    nk_str_len_char(&edit->string);\n                NK_ASSERT(select_end_ptr);\n                nk_edit_draw_text(out, style,\n                    area.x - edit->scrollbar.x,\n                    area.y + selection_offset_end.y - edit->scrollbar.y,\n                    selection_offset_end.x,\n                    begin, (int)(end - begin), row_height, font,\n                    background_color, text_color, nk_true);\n            }\n        }\n\n        /* cursor */\n        if (edit->select_start == edit->select_end)\n        {\n            if (edit->cursor >= nk_str_len(&edit->string) ||\n                (cursor_ptr && *cursor_ptr == '\\n')) {\n                /* draw cursor at end of line */\n                struct nk_rect cursor;\n                cursor.w = style->cursor_size;\n                cursor.h = font->height;\n                cursor.x = area.x + cursor_pos.x - edit->scrollbar.x;\n                cursor.y = area.y + cursor_pos.y + row_height/2.0f - cursor.h/2.0f;\n                cursor.y -= edit->scrollbar.y;\n                nk_fill_rect(out, cursor, 0, cursor_color);\n            } else {\n                /* draw cursor inside text */\n                int glyph_len;\n                struct nk_rect label;\n                struct nk_text txt;\n\n                nk_rune unicode;\n                NK_ASSERT(cursor_ptr);\n                glyph_len = nk_utf_decode(cursor_ptr, &unicode, 4);\n\n                label.x = area.x + cursor_pos.x - edit->scrollbar.x;\n                label.y = area.y + cursor_pos.y - edit->scrollbar.y;\n                label.w = font->width(font->userdata, font->height, cursor_ptr, glyph_len);\n                label.h = row_height;\n\n                txt.padding = nk_vec2(0,0);\n                txt.background = cursor_color;;\n                txt.text = cursor_text_color;\n                nk_fill_rect(out, label, 0, cursor_color);\n                nk_widget_text(out, label, cursor_ptr, glyph_len, &txt, NK_TEXT_LEFT, font);\n            }\n        }}\n    } else {\n        /* not active so just draw text */\n        int l = nk_str_len_char(&edit->string);\n        const char *begin = nk_str_get_const(&edit->string);\n\n        const struct nk_style_item *background;\n        struct nk_color background_color;\n        struct nk_color text_color;\n        nk_push_scissor(out, clip);\n        if (*state & NK_WIDGET_STATE_ACTIVED) {\n            background = &style->active;\n            text_color = style->text_active;\n        } else if (*state & NK_WIDGET_STATE_HOVER) {\n            background = &style->hover;\n            text_color = style->text_hover;\n        } else {\n            background = &style->normal;\n            text_color = style->text_normal;\n        }\n        if (background->type == NK_STYLE_ITEM_IMAGE)\n            background_color = nk_rgba(0,0,0,0);\n        else\n            background_color = background->data.color;\n\n        background_color = nk_rgb_factor(background_color, style->color_factor);\n        text_color = nk_rgb_factor(text_color, style->color_factor);\n\n        nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,\n            area.y - edit->scrollbar.y, 0, begin, l, row_height, font,\n            background_color, text_color, nk_false);\n    }\n    nk_push_scissor(out, old_clip);}\n    return ret;\n}\nNK_API void\nnk_edit_focus(struct nk_context *ctx, nk_flags flags)\n{\n    nk_hash hash;\n    struct nk_window *win;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return;\n\n    win = ctx->current;\n    hash = win->edit.seq;\n    win->edit.active = nk_true;\n    win->edit.name = hash;\n    if (flags & NK_EDIT_ALWAYS_INSERT_MODE)\n        win->edit.mode = NK_TEXT_EDIT_MODE_INSERT;\n}\nNK_API void\nnk_edit_unfocus(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return;\n\n    win = ctx->current;\n    win->edit.active = nk_false;\n    win->edit.name = 0;\n}\nNK_API nk_flags\nnk_edit_string(struct nk_context *ctx, nk_flags flags,\n    char *memory, int *len, int max, nk_plugin_filter filter)\n{\n    nk_hash hash;\n    nk_flags state;\n    struct nk_text_edit *edit;\n    struct nk_window *win;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(memory);\n    NK_ASSERT(len);\n    if (!ctx || !memory || !len)\n        return 0;\n\n    filter = (!filter) ? nk_filter_default: filter;\n    win = ctx->current;\n    hash = win->edit.seq;\n    edit = &ctx->text_edit;\n    nk_textedit_clear_state(&ctx->text_edit, (flags & NK_EDIT_MULTILINE)?\n        NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE, filter);\n\n    if (win->edit.active && hash == win->edit.name) {\n        if (flags & NK_EDIT_NO_CURSOR)\n            edit->cursor = nk_utf_len(memory, *len);\n        else edit->cursor = win->edit.cursor;\n        if (!(flags & NK_EDIT_SELECTABLE)) {\n            edit->select_start = win->edit.cursor;\n            edit->select_end = win->edit.cursor;\n        } else {\n            edit->select_start = win->edit.sel_start;\n            edit->select_end = win->edit.sel_end;\n        }\n        edit->mode = win->edit.mode;\n        edit->scrollbar.x = (float)win->edit.scrollbar.x;\n        edit->scrollbar.y = (float)win->edit.scrollbar.y;\n        edit->active = nk_true;\n    } else edit->active = nk_false;\n\n    max = NK_MAX(1, max);\n    *len = NK_MIN(*len, max-1);\n    nk_str_init_fixed(&edit->string, memory, (nk_size)max);\n    edit->string.buffer.allocated = (nk_size)*len;\n    edit->string.len = nk_utf_len(memory, *len);\n    state = nk_edit_buffer(ctx, flags, edit, filter);\n    *len = (int)edit->string.buffer.allocated;\n\n    if (edit->active) {\n        win->edit.cursor = edit->cursor;\n        win->edit.sel_start = edit->select_start;\n        win->edit.sel_end = edit->select_end;\n        win->edit.mode = edit->mode;\n        win->edit.scrollbar.x = (nk_uint)edit->scrollbar.x;\n        win->edit.scrollbar.y = (nk_uint)edit->scrollbar.y;\n    } return state;\n}\nNK_API nk_flags\nnk_edit_buffer(struct nk_context *ctx, nk_flags flags,\n    struct nk_text_edit *edit, nk_plugin_filter filter)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    struct nk_input *in;\n\n    enum nk_widget_layout_states state;\n    struct nk_rect bounds;\n\n    nk_flags ret_flags = 0;\n    unsigned char prev_state;\n    nk_hash hash;\n\n    /* make sure correct values */\n    NK_ASSERT(ctx);\n    NK_ASSERT(edit);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    state = nk_widget(&bounds, ctx);\n    if (!state) return state;\n    else if (state == NK_WIDGET_DISABLED)\n        flags |= NK_EDIT_READ_ONLY;\n    in = (win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n\n    /* check if edit is currently hot item */\n    hash = win->edit.seq++;\n    if (win->edit.active && hash == win->edit.name) {\n        if (flags & NK_EDIT_NO_CURSOR)\n            edit->cursor = edit->string.len;\n        if (!(flags & NK_EDIT_SELECTABLE)) {\n            edit->select_start = edit->cursor;\n            edit->select_end = edit->cursor;\n        }\n        if (flags & NK_EDIT_CLIPBOARD)\n            edit->clip = ctx->clip;\n        edit->active = (unsigned char)win->edit.active;\n    } else edit->active = nk_false;\n    edit->mode = win->edit.mode;\n\n    filter = (!filter) ? nk_filter_default: filter;\n    prev_state = (unsigned char)edit->active;\n    in = (flags & NK_EDIT_READ_ONLY) ? 0: in;\n    ret_flags = nk_do_edit(&ctx->last_widget_state, &win->buffer, bounds, flags,\n                    filter, edit, &style->edit, in, style->font);\n\n    if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n        ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_TEXT];\n    if (edit->active && prev_state != edit->active) {\n        /* current edit is now hot */\n        win->edit.active = nk_true;\n        win->edit.name = hash;\n    } else if (prev_state && !edit->active) {\n        /* current edit is now cold */\n        win->edit.active = nk_false;\n    } return ret_flags;\n}\nNK_API nk_flags\nnk_edit_string_zero_terminated(struct nk_context *ctx, nk_flags flags,\n    char *buffer, int max, nk_plugin_filter filter)\n{\n    nk_flags result;\n    int len = nk_strlen(buffer);\n    result = nk_edit_string(ctx, flags, buffer, &len, max, filter);\n    buffer[NK_MIN(NK_MAX(max-1,0), len)] = '\\0';\n    return result;\n}\n\n\n\n\n\n/* ===============================================================\n *\n *                              PROPERTY\n *\n * ===============================================================*/\nNK_LIB void\nnk_drag_behavior(nk_flags *state, const struct nk_input *in,\n    struct nk_rect drag, struct nk_property_variant *variant,\n    float inc_per_pixel)\n{\n    int left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;\n    int left_mouse_click_in_cursor = in &&\n        nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, drag, nk_true);\n\n    nk_widget_state_reset(state);\n    if (nk_input_is_mouse_hovering_rect(in, drag))\n        *state = NK_WIDGET_STATE_HOVERED;\n\n    if (left_mouse_down && left_mouse_click_in_cursor) {\n        float delta, pixels;\n        pixels = in->mouse.delta.x;\n        delta = pixels * inc_per_pixel;\n        switch (variant->kind) {\n        default: break;\n        case NK_PROPERTY_INT:\n            variant->value.i = variant->value.i + (int)delta;\n            variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);\n            break;\n        case NK_PROPERTY_FLOAT:\n            variant->value.f = variant->value.f + (float)delta;\n            variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);\n            break;\n        case NK_PROPERTY_DOUBLE:\n            variant->value.d = variant->value.d + (double)delta;\n            variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);\n            break;\n        }\n        *state = NK_WIDGET_STATE_ACTIVE;\n    }\n    if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, drag))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, drag))\n        *state |= NK_WIDGET_STATE_LEFT;\n}\nNK_LIB void\nnk_property_behavior(nk_flags *ws, const struct nk_input *in,\n    struct nk_rect property,  struct nk_rect label, struct nk_rect edit,\n    struct nk_rect empty, int *state, struct nk_property_variant *variant,\n    float inc_per_pixel)\n{\n    nk_widget_state_reset(ws);\n    if (in && *state == NK_PROPERTY_DEFAULT) {\n        if (nk_button_behavior(ws, edit, in, NK_BUTTON_DEFAULT))\n            *state = NK_PROPERTY_EDIT;\n        else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, label, nk_true))\n            *state = NK_PROPERTY_DRAG;\n        else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, empty, nk_true))\n            *state = NK_PROPERTY_DRAG;\n    }\n    if (*state == NK_PROPERTY_DRAG) {\n        nk_drag_behavior(ws, in, property, variant, inc_per_pixel);\n        if (!(*ws & NK_WIDGET_STATE_ACTIVED)) *state = NK_PROPERTY_DEFAULT;\n    }\n}\nNK_LIB void\nnk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style,\n    const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state,\n    const char *name, int len, const struct nk_user_font *font)\n{\n    struct nk_text text;\n    const struct nk_style_item *background;\n\n    /* select correct background and text color */\n    if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->active;\n        text.text = style->label_active;\n    } else if (state & NK_WIDGET_STATE_HOVER) {\n        background = &style->hover;\n        text.text = style->label_hover;\n    } else {\n        background = &style->normal;\n        text.text = style->label_normal;\n    }\n\n    text.text = nk_rgb_factor(text.text, style->color_factor);\n\n    /* draw background */\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            text.background = background->data.color;\n            nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));\n            nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));\n            break;\n    }\n\n    /* draw label */\n    text.padding = nk_vec2(0,0);\n    if (name && name[0] != '#') {\n        nk_widget_text(out, *label, name, len, &text, NK_TEXT_CENTERED, font);\n    }\n}\nNK_INTERN void\nnk_property_save(struct nk_property_variant *variant, char *buffer, int len)\n{\n    buffer[len] = '\\0';\n    switch (variant->kind) {\n    default: break;\n    case NK_PROPERTY_INT:\n        variant->value.i = nk_strtoi(buffer, 0);\n        variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);\n        break;\n    case NK_PROPERTY_FLOAT:\n        nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);\n        variant->value.f = nk_strtof(buffer, 0);\n        variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);\n        break;\n    case NK_PROPERTY_DOUBLE:\n        nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);\n        variant->value.d = NK_STRTOD(buffer, 0);\n        variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);\n        break;\n    }\n}\nNK_LIB void\nnk_do_property(nk_flags *ws,\n    struct nk_command_buffer *out, struct nk_rect property,\n    const char *name, struct nk_property_variant *variant,\n    float inc_per_pixel, char *buffer, int *len,\n    int *state, int *cursor, int *select_begin, int *select_end,\n    const struct nk_style_property *style,\n    enum nk_property_filter filter, struct nk_input *in,\n    const struct nk_user_font *font, struct nk_text_edit *text_edit,\n    enum nk_button_behavior behavior)\n{\n    const nk_plugin_filter filters[] = {\n        nk_filter_decimal,\n        nk_filter_float\n    };\n    nk_bool active, old;\n    int num_len = 0, name_len = 0;\n    char string[NK_MAX_NUMBER_BUFFER];\n    float size;\n\n    char *dst = 0;\n    int *length;\n\n    struct nk_rect left;\n    struct nk_rect right;\n    struct nk_rect label;\n    struct nk_rect edit;\n    struct nk_rect empty;\n\n    /* left decrement button */\n    left.h = font->height/2;\n    left.w = left.h;\n    left.x = property.x + style->border + style->padding.x;\n    left.y = property.y + style->border + property.h/2.0f - left.h/2;\n\n    /* text label */\n    if (name && name[0] != '#') {\n        name_len = nk_strlen(name);\n    }\n    size = font->width(font->userdata, font->height, name, name_len);\n    label.x = left.x + left.w + style->padding.x;\n    label.w = (float)size + 2 * style->padding.x;\n    label.y = property.y + style->border + style->padding.y;\n    label.h = property.h - (2 * style->border + 2 * style->padding.y);\n\n    /* right increment button */\n    right.y = left.y;\n    right.w = left.w;\n    right.h = left.h;\n    right.x = property.x + property.w - (right.w + style->padding.x);\n\n    /* edit */\n    if (*state == NK_PROPERTY_EDIT) {\n        size = font->width(font->userdata, font->height, buffer, *len);\n        size += style->edit.cursor_size;\n        length = len;\n        dst = buffer;\n    } else {\n        switch (variant->kind) {\n        default: break;\n        case NK_PROPERTY_INT:\n            nk_itoa(string, variant->value.i);\n            num_len = nk_strlen(string);\n            break;\n        case NK_PROPERTY_FLOAT:\n            NK_DTOA(string, (double)variant->value.f);\n            num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);\n            break;\n        case NK_PROPERTY_DOUBLE:\n            NK_DTOA(string, variant->value.d);\n            num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);\n            break;\n        }\n        size = font->width(font->userdata, font->height, string, num_len);\n        dst = string;\n        length = &num_len;\n    }\n\n    edit.w =  (float)size + 2 * style->padding.x;\n    edit.w = NK_MIN(edit.w, right.x - (label.x + label.w));\n    edit.x = right.x - (edit.w + style->padding.x);\n    edit.y = property.y + style->border;\n    edit.h = property.h - (2 * style->border);\n\n    /* empty left space activator */\n    empty.w = edit.x - (label.x + label.w);\n    empty.x = label.x + label.w;\n    empty.y = property.y;\n    empty.h = property.h;\n\n    /* update property */\n    old = (*state == NK_PROPERTY_EDIT);\n    nk_property_behavior(ws, in, property, label, edit, empty, state, variant, inc_per_pixel);\n\n    /* draw property */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_property(out, style, &property, &label, *ws, name, name_len, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n\n    /* execute right button  */\n    if (nk_do_button_symbol(ws, out, left, style->sym_left, behavior, &style->dec_button, in, font)) {\n        switch (variant->kind) {\n        default: break;\n        case NK_PROPERTY_INT:\n            variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i - variant->step.i, variant->max_value.i); break;\n        case NK_PROPERTY_FLOAT:\n            variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f - variant->step.f, variant->max_value.f); break;\n        case NK_PROPERTY_DOUBLE:\n            variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d - variant->step.d, variant->max_value.d); break;\n        }\n    }\n    /* execute left button  */\n    if (nk_do_button_symbol(ws, out, right, style->sym_right, behavior, &style->inc_button, in, font)) {\n        switch (variant->kind) {\n        default: break;\n        case NK_PROPERTY_INT:\n            variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i + variant->step.i, variant->max_value.i); break;\n        case NK_PROPERTY_FLOAT:\n            variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f + variant->step.f, variant->max_value.f); break;\n        case NK_PROPERTY_DOUBLE:\n            variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d + variant->step.d, variant->max_value.d); break;\n        }\n    }\n    if (!old && (*state == NK_PROPERTY_EDIT)) {\n        /* property has been activated so setup buffer */\n        NK_MEMCPY(buffer, dst, (nk_size)*length);\n        *cursor = nk_utf_len(buffer, *length);\n        *len = *length;\n        length = len;\n        dst = buffer;\n        active = 0;\n    } else active = (*state == NK_PROPERTY_EDIT);\n\n    /* execute and run text edit field */\n    nk_textedit_clear_state(text_edit, NK_TEXT_EDIT_SINGLE_LINE, filters[filter]);\n    text_edit->active = (unsigned char)active;\n    text_edit->string.len = *length;\n    text_edit->cursor = NK_CLAMP(0, *cursor, *length);\n    text_edit->select_start = NK_CLAMP(0,*select_begin, *length);\n    text_edit->select_end = NK_CLAMP(0,*select_end, *length);\n    text_edit->string.buffer.allocated = (nk_size)*length;\n    text_edit->string.buffer.memory.size = NK_MAX_NUMBER_BUFFER;\n    text_edit->string.buffer.memory.ptr = dst;\n    text_edit->string.buffer.size = NK_MAX_NUMBER_BUFFER;\n    text_edit->mode = NK_TEXT_EDIT_MODE_INSERT;\n    nk_do_edit(ws, out, edit, (int)NK_EDIT_FIELD|(int)NK_EDIT_AUTO_SELECT,\n        filters[filter], text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font);\n\n    *length = text_edit->string.len;\n    *cursor = text_edit->cursor;\n    *select_begin = text_edit->select_start;\n    *select_end = text_edit->select_end;\n    if (text_edit->active && nk_input_is_key_pressed(in, NK_KEY_ENTER))\n        text_edit->active = nk_false;\n\n    if (active && !text_edit->active) {\n        /* property is now not active so convert edit text to value*/\n        *state = NK_PROPERTY_DEFAULT;\n        nk_property_save(variant, buffer, *len);\n    }\n}\nNK_LIB struct nk_property_variant\nnk_property_variant_int(int value, int min_value, int max_value, int step)\n{\n    struct nk_property_variant result;\n    result.kind = NK_PROPERTY_INT;\n    result.value.i = value;\n    result.min_value.i = min_value;\n    result.max_value.i = max_value;\n    result.step.i = step;\n    return result;\n}\nNK_LIB struct nk_property_variant\nnk_property_variant_float(float value, float min_value, float max_value, float step)\n{\n    struct nk_property_variant result;\n    result.kind = NK_PROPERTY_FLOAT;\n    result.value.f = value;\n    result.min_value.f = min_value;\n    result.max_value.f = max_value;\n    result.step.f = step;\n    return result;\n}\nNK_LIB struct nk_property_variant\nnk_property_variant_double(double value, double min_value, double max_value,\n    double step)\n{\n    struct nk_property_variant result;\n    result.kind = NK_PROPERTY_DOUBLE;\n    result.value.d = value;\n    result.min_value.d = min_value;\n    result.max_value.d = max_value;\n    result.step.d = step;\n    return result;\n}\nNK_LIB void\nnk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant,\n    float inc_per_pixel, const enum nk_property_filter filter)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states s;\n    nk_bool hot;\n\n    int *state = 0;\n    nk_hash hash = 0;\n    char *buffer = 0;\n    int *len = 0;\n    int *cursor = 0;\n    int *select_begin = 0;\n    int *select_end = 0;\n    int old_state;\n    int prev_state;\n\n    char dummy_buffer[NK_MAX_NUMBER_BUFFER];\n    int dummy_state = NK_PROPERTY_DEFAULT;\n    int dummy_length = 0;\n    int dummy_cursor = 0;\n    int dummy_select_begin = 0;\n    int dummy_select_end = 0;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    style = &ctx->style;\n    s = nk_widget(&bounds, ctx);\n    if (!s) return;\n\n    /* calculate hash from name */\n    if (name[0] == '#') {\n        hash = nk_murmur_hash(name, (int)nk_strlen(name), win->property.seq++);\n        name++; /* special number hash */\n    } else hash = nk_murmur_hash(name, (int)nk_strlen(name), 42);\n\n    /* check if property is previously hot */\n    if (win->property.prev_state == NK_PROPERTY_EDIT && hash == win->property.prev_name) {\n        nk_property_save(variant, win->property.prev_buffer, win->property.prev_length);\n        win->property.prev_state = NK_PROPERTY_DEFAULT;\n    }\n\n    /* check if property is currently hot item */\n    hot = win->property.active && hash == win->property.name;\n    if (hot) {\n        buffer = win->property.buffer;\n        len = &win->property.length;\n        cursor = &win->property.cursor;\n        state = &win->property.state;\n        select_begin = &win->property.select_start;\n        select_end = &win->property.select_end;\n    } else {\n        buffer = dummy_buffer;\n        len = &dummy_length;\n        cursor = &dummy_cursor;\n        state = &dummy_state;\n        select_begin =  &dummy_select_begin;\n        select_end = &dummy_select_end;\n    }\n\n    /* execute property widget */\n    old_state = *state;\n    prev_state = win->property.state;\n    ctx->text_edit.clip = ctx->clip;\n    in = ((s == NK_WIDGET_ROM && !win->property.active) ||\n        layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED) ? 0 : &ctx->input;\n    nk_do_property(&ctx->last_widget_state, &win->buffer, bounds, name,\n        variant, inc_per_pixel, buffer, len, state, cursor, select_begin,\n        select_end, &style->property, filter, in, style->font, &ctx->text_edit,\n        ctx->button_behavior);\n\n    if (in && *state != NK_PROPERTY_DEFAULT && !hot) {\n        /* another property was active */\n        if (win->property.active /* && hash != win->property.name */) {\n            win->property.prev_state = prev_state;\n            win->property.prev_name = win->property.name;\n            win->property.prev_length = win->property.length;\n            NK_MEMCPY(win->property.prev_buffer, win->property.buffer, win->property.length);\n        }\n        /* current property is now hot */\n        win->property.active = 1;\n        NK_MEMCPY(win->property.buffer, buffer, (nk_size)*len);\n        win->property.length = *len;\n        win->property.cursor = *cursor;\n        win->property.state = *state;\n        win->property.name = hash;\n        win->property.select_start = *select_begin;\n        win->property.select_end = *select_end;\n        win->edit.active = nk_true;\n        if (*state == NK_PROPERTY_DRAG) {\n            ctx->input.mouse.grab = nk_true;\n            ctx->input.mouse.grabbed = nk_true;\n        }\n    }\n    /* check if previously active property is now inactive */\n    if (*state == NK_PROPERTY_DEFAULT && old_state != NK_PROPERTY_DEFAULT) {\n        if (old_state == NK_PROPERTY_DRAG) {\n            ctx->input.mouse.grab = nk_false;\n            ctx->input.mouse.grabbed = nk_false;\n            ctx->input.mouse.ungrab = nk_true;\n        }\n        win->property.select_start = 0;\n        win->property.select_end = 0;\n        win->property.active = 0;\n        win->edit.active = nk_false;\n    }\n}\nNK_API nk_bool\nnk_property_int(struct nk_context *ctx, const char *name,\n    int min, int *val, int max, int step, float inc_per_pixel)\n{\n    struct nk_property_variant variant;\n    nk_bool changed;\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n    NK_ASSERT(val);\n\n    if (!ctx || !ctx->current || !name || !val) return nk_false;\n    variant = nk_property_variant_int(*val, min, max, step);\n    nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);\n    changed = variant.value.i != *val;\n    *val = variant.value.i;\n    return changed;\n}\nNK_API nk_bool\nnk_property_float(struct nk_context *ctx, const char *name,\n    float min, float *val, float max, float step, float inc_per_pixel)\n{\n    struct nk_property_variant variant;\n    nk_bool changed;\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n    NK_ASSERT(val);\n\n    if (!ctx || !ctx->current || !name || !val) return nk_false;\n    variant = nk_property_variant_float(*val, min, max, step);\n    nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);\n    changed = variant.value.f != *val;\n    *val = variant.value.f;\n    return changed;\n}\nNK_API nk_bool\nnk_property_double(struct nk_context *ctx, const char *name,\n    double min, double *val, double max, double step, float inc_per_pixel)\n{\n    struct nk_property_variant variant;\n    nk_bool changed;\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n    NK_ASSERT(val);\n\n    if (!ctx || !ctx->current || !name || !val) return nk_false;\n    variant = nk_property_variant_double(*val, min, max, step);\n    nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);\n    changed = variant.value.d != *val;\n    *val = variant.value.d;\n    return changed;\n}\nNK_API int\nnk_propertyi(struct nk_context *ctx, const char *name, int min, int val,\n    int max, int step, float inc_per_pixel)\n{\n    struct nk_property_variant variant;\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n\n    if (!ctx || !ctx->current || !name) return val;\n    variant = nk_property_variant_int(val, min, max, step);\n    nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);\n    val = variant.value.i;\n    return val;\n}\nNK_API float\nnk_propertyf(struct nk_context *ctx, const char *name, float min,\n    float val, float max, float step, float inc_per_pixel)\n{\n    struct nk_property_variant variant;\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n\n    if (!ctx || !ctx->current || !name) return val;\n    variant = nk_property_variant_float(val, min, max, step);\n    nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);\n    val = variant.value.f;\n    return val;\n}\nNK_API double\nnk_propertyd(struct nk_context *ctx, const char *name, double min,\n    double val, double max, double step, float inc_per_pixel)\n{\n    struct nk_property_variant variant;\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n\n    if (!ctx || !ctx->current || !name) return val;\n    variant = nk_property_variant_double(val, min, max, step);\n    nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);\n    val = variant.value.d;\n    return val;\n}\n\n\n\n\n\n/* ==============================================================\n *\n *                          CHART\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type,\n    struct nk_color color, struct nk_color highlight,\n    int count, float min_value, float max_value)\n{\n    struct nk_window *win;\n    struct nk_chart *chart;\n    const struct nk_style *config;\n    const struct nk_style_chart *style;\n\n    const struct nk_style_item *background;\n    struct nk_rect bounds = {0, 0, 0, 0};\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n\n    if (!ctx || !ctx->current || !ctx->current->layout) return 0;\n    if (!nk_widget(&bounds, ctx)) {\n        chart = &ctx->current->layout->chart;\n        nk_zero(chart, sizeof(*chart));\n        return 0;\n    }\n\n    win = ctx->current;\n    config = &ctx->style;\n    chart = &win->layout->chart;\n    style = &config->chart;\n\n    /* setup basic generic chart  */\n    nk_zero(chart, sizeof(*chart));\n    chart->x = bounds.x + style->padding.x;\n    chart->y = bounds.y + style->padding.y;\n    chart->w = bounds.w - 2 * style->padding.x;\n    chart->h = bounds.h - 2 * style->padding.y;\n    chart->w = NK_MAX(chart->w, 2 * style->padding.x);\n    chart->h = NK_MAX(chart->h, 2 * style->padding.y);\n\n    /* add first slot into chart */\n    {struct nk_chart_slot *slot = &chart->slots[chart->slot++];\n    slot->type = type;\n    slot->count = count;\n    slot->color = nk_rgb_factor(color, style->color_factor);\n    slot->highlight = highlight;\n    slot->min = NK_MIN(min_value, max_value);\n    slot->max = NK_MAX(min_value, max_value);\n    slot->range = slot->max - slot->min;\n    slot->show_markers = style->show_markers;}\n\n    /* draw chart background */\n    background = &style->background;\n\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(&win->buffer, bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(&win->buffer, bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(&win->buffer, bounds, style->rounding, nk_rgb_factor(style->border_color, style->color_factor));\n            nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border),\n                style->rounding, nk_rgb_factor(style->background.data.color, style->color_factor));\n            break;\n    }\n    return 1;\n}\nNK_API nk_bool\nnk_chart_begin(struct nk_context *ctx, const enum nk_chart_type type,\n    int count, float min_value, float max_value)\n{\n    return nk_chart_begin_colored(ctx, type, ctx->style.chart.color,\n                ctx->style.chart.selected_color, count, min_value, max_value);\n}\nNK_API void\nnk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type type,\n    struct nk_color color, struct nk_color highlight,\n    int count, float min_value, float max_value)\n{\n    const struct nk_style_chart* style;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    NK_ASSERT(ctx->current->layout->chart.slot < NK_CHART_MAX_SLOT);\n    if (!ctx || !ctx->current || !ctx->current->layout) return;\n    if (ctx->current->layout->chart.slot >= NK_CHART_MAX_SLOT) return;\n\n    style = &ctx->style.chart;\n\n    /* add another slot into the graph */\n    {struct nk_chart *chart = &ctx->current->layout->chart;\n    struct nk_chart_slot *slot = &chart->slots[chart->slot++];\n    slot->type = type;\n    slot->count = count;\n    slot->color = nk_rgb_factor(color, style->color_factor);\n    slot->highlight = highlight;\n    slot->min = NK_MIN(min_value, max_value);\n    slot->max = NK_MAX(min_value, max_value);\n    slot->range = slot->max - slot->min;\n    slot->show_markers = style->show_markers;}\n}\nNK_API void\nnk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type type,\n    int count, float min_value, float max_value)\n{\n    nk_chart_add_slot_colored(ctx, type, ctx->style.chart.color,\n        ctx->style.chart.selected_color, count, min_value, max_value);\n}\nNK_INTERN nk_flags\nnk_chart_push_line(struct nk_context *ctx, struct nk_window *win,\n    struct nk_chart *g, float value, int slot)\n{\n    struct nk_panel *layout = win->layout;\n    const struct nk_input *i = ctx->current->widgets_disabled ? 0 : &ctx->input;\n    struct nk_command_buffer *out = &win->buffer;\n\n    nk_flags ret = 0;\n    struct nk_vec2 cur;\n    struct nk_rect bounds;\n    struct nk_color color;\n    float step;\n    float range;\n    float ratio;\n\n    NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);\n    step = g->w / (float)g->slots[slot].count;\n    range = g->slots[slot].max - g->slots[slot].min;\n    ratio = (value - g->slots[slot].min) / range;\n\n    if (g->slots[slot].index == 0) {\n        /* first data point does not have a connection */\n        g->slots[slot].last.x = g->x;\n        g->slots[slot].last.y = (g->y + g->h) - ratio * (float)g->h;\n\n        bounds.x = g->slots[slot].last.x - 2;\n        bounds.y = g->slots[slot].last.y - 2;\n        bounds.w = bounds.h = 4;\n\n        color = g->slots[slot].color;\n        if (!(layout->flags & NK_WINDOW_ROM) && i &&\n            NK_INBOX(i->mouse.pos.x,i->mouse.pos.y, g->slots[slot].last.x-3, g->slots[slot].last.y-3, 6, 6)){\n            ret = nk_input_is_mouse_hovering_rect(i, bounds) ? NK_CHART_HOVERING : 0;\n            ret |= (i->mouse.buttons[NK_BUTTON_LEFT].down &&\n                i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;\n            color = g->slots[slot].highlight;\n        }\n        if (g->slots[slot].show_markers) {\n            nk_fill_rect(out, bounds, 0, color);\n        }\n        g->slots[slot].index += 1;\n        return ret;\n    }\n\n    /* draw a line between the last data point and the new one */\n    color = g->slots[slot].color;\n    cur.x = g->x + (float)(step * (float)g->slots[slot].index);\n    cur.y = (g->y + g->h) - (ratio * (float)g->h);\n    nk_stroke_line(out, g->slots[slot].last.x, g->slots[slot].last.y, cur.x, cur.y, 1.0f, color);\n\n    bounds.x = cur.x - 3;\n    bounds.y = cur.y - 3;\n    bounds.w = bounds.h = 6;\n\n    /* user selection of current data point */\n    if (!(layout->flags & NK_WINDOW_ROM)) {\n        if (nk_input_is_mouse_hovering_rect(i, bounds)) {\n            ret = NK_CHART_HOVERING;\n            ret |= (!i->mouse.buttons[NK_BUTTON_LEFT].down &&\n                i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;\n            color = g->slots[slot].highlight;\n        }\n    }\n    if (g->slots[slot].show_markers) {\n        nk_fill_rect(out, nk_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color);\n    }\n\n    /* save current data point position */\n    g->slots[slot].last.x = cur.x;\n    g->slots[slot].last.y = cur.y;\n    g->slots[slot].index  += 1;\n    return ret;\n}\nNK_INTERN nk_flags\nnk_chart_push_column(const struct nk_context *ctx, struct nk_window *win,\n    struct nk_chart *chart, float value, int slot)\n{\n    struct nk_command_buffer *out = &win->buffer;\n    const struct nk_input *in = ctx->current->widgets_disabled ? 0 : &ctx->input;\n    struct nk_panel *layout = win->layout;\n\n    float ratio;\n    nk_flags ret = 0;\n    struct nk_color color;\n    struct nk_rect item = {0,0,0,0};\n\n    NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);\n    if (chart->slots[slot].index  >= chart->slots[slot].count)\n        return nk_false;\n    if (chart->slots[slot].count) {\n        float padding = (float)(chart->slots[slot].count-1);\n        item.w = (chart->w - padding) / (float)(chart->slots[slot].count);\n    }\n\n    /* calculate bounds of current bar chart entry */\n    color = chart->slots[slot].color;;\n    item.h = chart->h * NK_ABS((value/chart->slots[slot].range));\n    if (value >= 0) {\n        ratio = (value + NK_ABS(chart->slots[slot].min)) / NK_ABS(chart->slots[slot].range);\n        item.y = (chart->y + chart->h) - chart->h * ratio;\n    } else {\n        ratio = (value - chart->slots[slot].max) / chart->slots[slot].range;\n        item.y = chart->y + (chart->h * NK_ABS(ratio)) - item.h;\n    }\n    item.x = chart->x + ((float)chart->slots[slot].index * item.w);\n    item.x = item.x + ((float)chart->slots[slot].index);\n\n    /* user chart bar selection */\n    if (!(layout->flags & NK_WINDOW_ROM) && in &&\n        NK_INBOX(in->mouse.pos.x,in->mouse.pos.y,item.x,item.y,item.w,item.h)) {\n        ret = NK_CHART_HOVERING;\n        ret |= (!in->mouse.buttons[NK_BUTTON_LEFT].down &&\n                in->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;\n        color = chart->slots[slot].highlight;\n    }\n    nk_fill_rect(out, item, 0, color);\n    chart->slots[slot].index += 1;\n    return ret;\n}\nNK_API nk_flags\nnk_chart_push_slot(struct nk_context *ctx, float value, int slot)\n{\n    nk_flags flags;\n    struct nk_window *win;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);\n    NK_ASSERT(slot < ctx->current->layout->chart.slot);\n    if (!ctx || !ctx->current || slot >= NK_CHART_MAX_SLOT) return nk_false;\n    if (slot >= ctx->current->layout->chart.slot) return nk_false;\n\n    win = ctx->current;\n    if (win->layout->chart.slot < slot) return nk_false;\n    switch (win->layout->chart.slots[slot].type) {\n    case NK_CHART_LINES:\n        flags = nk_chart_push_line(ctx, win, &win->layout->chart, value, slot); break;\n    case NK_CHART_COLUMN:\n        flags = nk_chart_push_column(ctx, win, &win->layout->chart, value, slot); break;\n    default:\n    case NK_CHART_MAX:\n        flags = 0;\n    }\n    return flags;\n}\nNK_API nk_flags\nnk_chart_push(struct nk_context *ctx, float value)\n{\n    return nk_chart_push_slot(ctx, value, 0);\n}\nNK_API void\nnk_chart_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_chart *chart;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return;\n\n    win = ctx->current;\n    chart = &win->layout->chart;\n    NK_MEMSET(chart, 0, sizeof(*chart));\n    return;\n}\nNK_API void\nnk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values,\n    int count, int offset)\n{\n    int i = 0;\n    float min_value;\n    float max_value;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(values);\n    if (!ctx || !values || !count) return;\n\n    min_value = values[offset];\n    max_value = values[offset];\n    for (i = 0; i < count; ++i) {\n        min_value = NK_MIN(values[i + offset], min_value);\n        max_value = NK_MAX(values[i + offset], max_value);\n    }\n\n    if (nk_chart_begin(ctx, type, count, min_value, max_value)) {\n        for (i = 0; i < count; ++i)\n            nk_chart_push(ctx, values[i + offset]);\n        nk_chart_end(ctx);\n    }\n}\nNK_API void\nnk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata,\n    float(*value_getter)(void* user, int index), int count, int offset)\n{\n    int i = 0;\n    float min_value;\n    float max_value;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(value_getter);\n    if (!ctx || !value_getter || !count) return;\n\n    max_value = min_value = value_getter(userdata, offset);\n    for (i = 0; i < count; ++i) {\n        float value = value_getter(userdata, i + offset);\n        min_value = NK_MIN(value, min_value);\n        max_value = NK_MAX(value, max_value);\n    }\n\n    if (nk_chart_begin(ctx, type, count, min_value, max_value)) {\n        for (i = 0; i < count; ++i)\n            nk_chart_push(ctx, value_getter(userdata, i + offset));\n        nk_chart_end(ctx);\n    }\n}\n\n\n\n\n\n/* ==============================================================\n *\n *                          COLOR PICKER\n *\n * ===============================================================*/\nNK_LIB nk_bool\nnk_color_picker_behavior(nk_flags *state,\n    const struct nk_rect *bounds, const struct nk_rect *matrix,\n    const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar,\n    struct nk_colorf *color, const struct nk_input *in)\n{\n    float hsva[4];\n    nk_bool value_changed = 0;\n    nk_bool hsv_changed = 0;\n\n    NK_ASSERT(state);\n    NK_ASSERT(matrix);\n    NK_ASSERT(hue_bar);\n    NK_ASSERT(color);\n\n    /* color matrix */\n    nk_colorf_hsva_fv(hsva, *color);\n    if (nk_button_behavior(state, *matrix, in, NK_BUTTON_REPEATER)) {\n        hsva[1] = NK_SATURATE((in->mouse.pos.x - matrix->x) / (matrix->w-1));\n        hsva[2] = 1.0f - NK_SATURATE((in->mouse.pos.y - matrix->y) / (matrix->h-1));\n        value_changed = hsv_changed = 1;\n    }\n    /* hue bar */\n    if (nk_button_behavior(state, *hue_bar, in, NK_BUTTON_REPEATER)) {\n        hsva[0] = NK_SATURATE((in->mouse.pos.y - hue_bar->y) / (hue_bar->h-1));\n        value_changed = hsv_changed = 1;\n    }\n    /* alpha bar */\n    if (alpha_bar) {\n        if (nk_button_behavior(state, *alpha_bar, in, NK_BUTTON_REPEATER)) {\n            hsva[3] = 1.0f - NK_SATURATE((in->mouse.pos.y - alpha_bar->y) / (alpha_bar->h-1));\n            value_changed = 1;\n        }\n    }\n    nk_widget_state_reset(state);\n    if (hsv_changed) {\n        *color = nk_hsva_colorfv(hsva);\n        *state = NK_WIDGET_STATE_ACTIVE;\n    }\n    if (value_changed) {\n        color->a = hsva[3];\n        *state = NK_WIDGET_STATE_ACTIVE;\n    }\n    /* set color picker widget state */\n    if (nk_input_is_mouse_hovering_rect(in, *bounds))\n        *state = NK_WIDGET_STATE_HOVERED;\n    if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *bounds))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, *bounds))\n        *state |= NK_WIDGET_STATE_LEFT;\n    return value_changed;\n}\nNK_LIB void\nnk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix,\n    const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar,\n    struct nk_colorf col)\n{\n    NK_STORAGE const struct nk_color black = {0,0,0,255};\n    NK_STORAGE const struct nk_color white = {255, 255, 255, 255};\n    NK_STORAGE const struct nk_color black_trans = {0,0,0,0};\n\n    const float crosshair_size = 7.0f;\n    struct nk_color temp;\n    float hsva[4];\n    float line_y;\n    int i;\n\n    NK_ASSERT(o);\n    NK_ASSERT(matrix);\n    NK_ASSERT(hue_bar);\n\n    /* draw hue bar */\n    nk_colorf_hsva_fv(hsva, col);\n    for (i = 0; i < 6; ++i) {\n        NK_GLOBAL const struct nk_color hue_colors[] = {\n            {255, 0, 0, 255}, {255,255,0,255}, {0,255,0,255}, {0, 255,255,255},\n            {0,0,255,255}, {255, 0, 255, 255}, {255, 0, 0, 255}\n        };\n        nk_fill_rect_multi_color(o,\n            nk_rect(hue_bar->x, hue_bar->y + (float)i * (hue_bar->h/6.0f) + 0.5f,\n                hue_bar->w, (hue_bar->h/6.0f) + 0.5f), hue_colors[i], hue_colors[i],\n                hue_colors[i+1], hue_colors[i+1]);\n    }\n    line_y = (float)(int)(hue_bar->y + hsva[0] * matrix->h + 0.5f);\n    nk_stroke_line(o, hue_bar->x-1, line_y, hue_bar->x + hue_bar->w + 2,\n        line_y, 1, nk_rgb(255,255,255));\n\n    /* draw alpha bar */\n    if (alpha_bar) {\n        float alpha = NK_SATURATE(col.a);\n        line_y = (float)(int)(alpha_bar->y +  (1.0f - alpha) * matrix->h + 0.5f);\n\n        nk_fill_rect_multi_color(o, *alpha_bar, white, white, black, black);\n        nk_stroke_line(o, alpha_bar->x-1, line_y, alpha_bar->x + alpha_bar->w + 2,\n            line_y, 1, nk_rgb(255,255,255));\n    }\n\n    /* draw color matrix */\n    temp = nk_hsv_f(hsva[0], 1.0f, 1.0f);\n    nk_fill_rect_multi_color(o, *matrix, white, temp, temp, white);\n    nk_fill_rect_multi_color(o, *matrix, black_trans, black_trans, black, black);\n\n    /* draw cross-hair */\n    {struct nk_vec2 p; float S = hsva[1]; float V = hsva[2];\n    p.x = (float)(int)(matrix->x + S * matrix->w);\n    p.y = (float)(int)(matrix->y + (1.0f - V) * matrix->h);\n    nk_stroke_line(o, p.x - crosshair_size, p.y, p.x-2, p.y, 1.0f, white);\n    nk_stroke_line(o, p.x + crosshair_size + 1, p.y, p.x+3, p.y, 1.0f, white);\n    nk_stroke_line(o, p.x, p.y + crosshair_size + 1, p.x, p.y+3, 1.0f, white);\n    nk_stroke_line(o, p.x, p.y - crosshair_size, p.x, p.y-2, 1.0f, white);}\n}\nNK_LIB nk_bool\nnk_do_color_picker(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_colorf *col,\n    enum nk_color_format fmt, struct nk_rect bounds,\n    struct nk_vec2 padding, const struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    int ret = 0;\n    struct nk_rect matrix;\n    struct nk_rect hue_bar;\n    struct nk_rect alpha_bar;\n    float bar_w;\n\n    NK_ASSERT(out);\n    NK_ASSERT(col);\n    NK_ASSERT(state);\n    NK_ASSERT(font);\n    if (!out || !col || !state || !font)\n        return ret;\n\n    bar_w = font->height;\n    bounds.x += padding.x;\n    bounds.y += padding.x;\n    bounds.w -= 2 * padding.x;\n    bounds.h -= 2 * padding.y;\n\n    matrix.x = bounds.x;\n    matrix.y = bounds.y;\n    matrix.h = bounds.h;\n    matrix.w = bounds.w - (3 * padding.x + 2 * bar_w);\n\n    hue_bar.w = bar_w;\n    hue_bar.y = bounds.y;\n    hue_bar.h = matrix.h;\n    hue_bar.x = matrix.x + matrix.w + padding.x;\n\n    alpha_bar.x = hue_bar.x + hue_bar.w + padding.x;\n    alpha_bar.y = bounds.y;\n    alpha_bar.w = bar_w;\n    alpha_bar.h = matrix.h;\n\n    ret = nk_color_picker_behavior(state, &bounds, &matrix, &hue_bar,\n        (fmt == NK_RGBA) ? &alpha_bar:0, col, in);\n    nk_draw_color_picker(out, &matrix, &hue_bar, (fmt == NK_RGBA) ? &alpha_bar:0, *col);\n    return ret;\n}\nNK_API nk_bool\nnk_color_pick(struct nk_context * ctx, struct nk_colorf *color,\n    enum nk_color_format fmt)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_style *config;\n    const struct nk_input *in;\n\n    enum nk_widget_layout_states state;\n    struct nk_rect bounds;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(color);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !color)\n        return 0;\n\n    win = ctx->current;\n    config = &ctx->style;\n    layout = win->layout;\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_color_picker(&ctx->last_widget_state, &win->buffer, color, fmt, bounds,\n                nk_vec2(0,0), in, config->font);\n}\nNK_API struct nk_colorf\nnk_color_picker(struct nk_context *ctx, struct nk_colorf color,\n    enum nk_color_format fmt)\n{\n    nk_color_pick(ctx, &color, fmt);\n    return color;\n}\n\n\n\n\n\n/* ==============================================================\n *\n *                          COMBO\n *\n * ===============================================================*/\nNK_INTERN nk_bool\nnk_combo_begin(struct nk_context *ctx, struct nk_window *win,\n    struct nk_vec2 size, nk_bool is_clicked, struct nk_rect header)\n{\n    struct nk_window *popup;\n    int is_open = 0;\n    int is_active = 0;\n    struct nk_rect body;\n    nk_hash hash;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    popup = win->popup.win;\n    body.x = header.x;\n    body.w = size.x;\n    body.y = header.y + header.h-ctx->style.window.combo_border;\n    body.h = size.y;\n\n    hash = win->popup.combo_count++;\n    is_open = (popup) ? nk_true:nk_false;\n    is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_COMBO);\n    if ((is_clicked && is_open && !is_active) || (is_open && !is_active) ||\n        (!is_open && !is_active && !is_clicked)) return 0;\n    if (!nk_nonblock_begin(ctx, 0, body,\n        (is_clicked && is_open)?nk_rect(0,0,0,0):header, NK_PANEL_COMBO)) return 0;\n\n    win->popup.type = NK_PANEL_COMBO;\n    win->popup.name = hash;\n    return 1;\n}\nNK_API nk_bool\nnk_combo_begin_text(struct nk_context *ctx, const char *selected, int len,\n    struct nk_vec2 size)\n{\n    const struct nk_input *in;\n    struct nk_window *win;\n    struct nk_style *style;\n\n    enum nk_widget_layout_states s;\n    int is_clicked = nk_false;\n    struct nk_rect header;\n    const struct nk_style_item *background;\n    struct nk_text text;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(selected);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !selected)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    s = nk_widget(&header, ctx);\n    if (s == NK_WIDGET_INVALID)\n        return 0;\n\n    in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;\n    if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))\n        is_clicked = nk_true;\n\n    /* draw combo box header background and border */\n    if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->combo.active;\n        text.text = style->combo.label_active;\n    } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {\n        background = &style->combo.hover;\n        text.text = style->combo.label_hover;\n    } else {\n        background = &style->combo.normal;\n        text.text = style->combo.label_normal;\n    }\n\n    text.text = nk_rgb_factor(text.text, style->combo.color_factor);\n\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            text.background = background->data.color;\n            nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));\n            nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));\n            break;\n    }\n    {\n        /* print currently selected text item */\n        struct nk_rect label;\n        struct nk_rect button;\n        struct nk_rect content;\n        int draw_button_symbol;\n\n        enum nk_symbol_type sym;\n        if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n            sym = style->combo.sym_hover;\n        else if (is_clicked)\n            sym = style->combo.sym_active;\n        else\n            sym = style->combo.sym_normal;\n\n        /* represents whether or not the combo's button symbol should be drawn */\n        draw_button_symbol = sym != NK_SYMBOL_NONE;\n\n        /* calculate button */\n        button.w = header.h - 2 * style->combo.button_padding.y;\n        button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;\n        button.y = header.y + style->combo.button_padding.y;\n        button.h = button.w;\n\n        content.x = button.x + style->combo.button.padding.x;\n        content.y = button.y + style->combo.button.padding.y;\n        content.w = button.w - 2 * style->combo.button.padding.x;\n        content.h = button.h - 2 * style->combo.button.padding.y;\n\n        /* draw selected label */\n        text.padding = nk_vec2(0,0);\n        label.x = header.x + style->combo.content_padding.x;\n        label.y = header.y + style->combo.content_padding.y;\n        label.h = header.h - 2 * style->combo.content_padding.y;\n        if (draw_button_symbol)\n            label.w = button.x - (style->combo.content_padding.x + style->combo.spacing.x) - label.x;\n        else\n            label.w = header.w - 2 * style->combo.content_padding.x;\n        nk_widget_text(&win->buffer, label, selected, len, &text,\n            NK_TEXT_LEFT, ctx->style.font);\n\n        /* draw open/close button */\n        if (draw_button_symbol)\n            nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,\n                &ctx->style.combo.button, sym, style->font);\n    }\n    return nk_combo_begin(ctx, win, size, is_clicked, header);\n}\nNK_API nk_bool\nnk_combo_begin_label(struct nk_context *ctx, const char *selected, struct nk_vec2 size)\n{\n    return nk_combo_begin_text(ctx, selected, nk_strlen(selected), size);\n}\nNK_API nk_bool\nnk_combo_begin_color(struct nk_context *ctx, struct nk_color color, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    const struct nk_input *in;\n\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    enum nk_widget_layout_states s;\n    const struct nk_style_item *background;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    s = nk_widget(&header, ctx);\n    if (s == NK_WIDGET_INVALID)\n        return 0;\n\n    in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;\n    if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))\n        is_clicked = nk_true;\n\n    /* draw combo box header background and border */\n    if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED)\n        background = &style->combo.active;\n    else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n        background = &style->combo.hover;\n    else background = &style->combo.normal;\n\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));\n            nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));\n            break;\n    }\n    {\n        struct nk_rect content;\n        struct nk_rect button;\n        struct nk_rect bounds;\n        int draw_button_symbol;\n\n        enum nk_symbol_type sym;\n        if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n            sym = style->combo.sym_hover;\n        else if (is_clicked)\n            sym = style->combo.sym_active;\n        else sym = style->combo.sym_normal;\n\n        /* represents whether or not the combo's button symbol should be drawn */\n        draw_button_symbol = sym != NK_SYMBOL_NONE;\n\n        /* calculate button */\n        button.w = header.h - 2 * style->combo.button_padding.y;\n        button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;\n        button.y = header.y + style->combo.button_padding.y;\n        button.h = button.w;\n\n        content.x = button.x + style->combo.button.padding.x;\n        content.y = button.y + style->combo.button.padding.y;\n        content.w = button.w - 2 * style->combo.button.padding.x;\n        content.h = button.h - 2 * style->combo.button.padding.y;\n\n        /* draw color */\n        bounds.h = header.h - 4 * style->combo.content_padding.y;\n        bounds.y = header.y + 2 * style->combo.content_padding.y;\n        bounds.x = header.x + 2 * style->combo.content_padding.x;\n        if (draw_button_symbol)\n            bounds.w = (button.x - (style->combo.content_padding.x + style->combo.spacing.x)) - bounds.x;\n        else\n            bounds.w = header.w - 4 * style->combo.content_padding.x;\n        nk_fill_rect(&win->buffer, bounds, 0, nk_rgb_factor(color, style->combo.color_factor));\n\n        /* draw open/close button */\n        if (draw_button_symbol)\n            nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,\n                &ctx->style.combo.button, sym, style->font);\n    }\n    return nk_combo_begin(ctx, win, size, is_clicked, header);\n}\nNK_API nk_bool\nnk_combo_begin_symbol(struct nk_context *ctx, enum nk_symbol_type symbol, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    const struct nk_input *in;\n\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    enum nk_widget_layout_states s;\n    const struct nk_style_item *background;\n    struct nk_color sym_background;\n    struct nk_color symbol_color;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    s = nk_widget(&header, ctx);\n    if (s == NK_WIDGET_INVALID)\n        return 0;\n\n    in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;\n    if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))\n        is_clicked = nk_true;\n\n    /* draw combo box header background and border */\n    if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->combo.active;\n        symbol_color = style->combo.symbol_active;\n    } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {\n        background = &style->combo.hover;\n        symbol_color = style->combo.symbol_hover;\n    } else {\n        background = &style->combo.normal;\n        symbol_color = style->combo.symbol_hover;\n    }\n\n    symbol_color = nk_rgb_factor(symbol_color, style->combo.color_factor);\n\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            sym_background = nk_rgba(0, 0, 0, 0);\n            nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            sym_background = nk_rgba(0, 0, 0, 0);\n            nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            sym_background = background->data.color;\n            nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));\n            nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));\n            break;\n    }\n    {\n        struct nk_rect bounds = {0,0,0,0};\n        struct nk_rect content;\n        struct nk_rect button;\n\n        enum nk_symbol_type sym;\n        if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n            sym = style->combo.sym_hover;\n        else if (is_clicked)\n            sym = style->combo.sym_active;\n        else sym = style->combo.sym_normal;\n\n        /* calculate button */\n        button.w = header.h - 2 * style->combo.button_padding.y;\n        button.x = (header.x + header.w - header.h) - style->combo.button_padding.y;\n        button.y = header.y + style->combo.button_padding.y;\n        button.h = button.w;\n\n        content.x = button.x + style->combo.button.padding.x;\n        content.y = button.y + style->combo.button.padding.y;\n        content.w = button.w - 2 * style->combo.button.padding.x;\n        content.h = button.h - 2 * style->combo.button.padding.y;\n\n        /* draw symbol */\n        bounds.h = header.h - 2 * style->combo.content_padding.y;\n        bounds.y = header.y + style->combo.content_padding.y;\n        bounds.x = header.x + style->combo.content_padding.x;\n        bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;\n        nk_draw_symbol(&win->buffer, symbol, bounds, sym_background, symbol_color,\n            1.0f, style->font);\n\n        /* draw open/close button */\n        nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state,\n            &ctx->style.combo.button, sym, style->font);\n    }\n    return nk_combo_begin(ctx, win, size, is_clicked, header);\n}\nNK_API nk_bool\nnk_combo_begin_symbol_text(struct nk_context *ctx, const char *selected, int len,\n    enum nk_symbol_type symbol, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    struct nk_input *in;\n\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    enum nk_widget_layout_states s;\n    const struct nk_style_item *background;\n    struct nk_color symbol_color;\n    struct nk_text text;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    s = nk_widget(&header, ctx);\n    if (!s) return 0;\n\n    in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;\n    if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))\n        is_clicked = nk_true;\n\n    /* draw combo box header background and border */\n    if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->combo.active;\n        symbol_color = style->combo.symbol_active;\n        text.text = style->combo.label_active;\n    } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {\n        background = &style->combo.hover;\n        symbol_color = style->combo.symbol_hover;\n        text.text = style->combo.label_hover;\n    } else {\n        background = &style->combo.normal;\n        symbol_color = style->combo.symbol_normal;\n        text.text = style->combo.label_normal;\n    }\n\n    text.text = nk_rgb_factor(text.text, style->combo.color_factor);\n    symbol_color = nk_rgb_factor(symbol_color, style->combo.color_factor);\n\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            text.background = background->data.color;\n            nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));\n            nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));\n            break;\n    }\n    {\n        struct nk_rect content;\n        struct nk_rect button;\n        struct nk_rect label;\n        struct nk_rect image;\n\n        enum nk_symbol_type sym;\n        if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n            sym = style->combo.sym_hover;\n        else if (is_clicked)\n            sym = style->combo.sym_active;\n        else sym = style->combo.sym_normal;\n\n        /* calculate button */\n        button.w = header.h - 2 * style->combo.button_padding.y;\n        button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;\n        button.y = header.y + style->combo.button_padding.y;\n        button.h = button.w;\n\n        content.x = button.x + style->combo.button.padding.x;\n        content.y = button.y + style->combo.button.padding.y;\n        content.w = button.w - 2 * style->combo.button.padding.x;\n        content.h = button.h - 2 * style->combo.button.padding.y;\n        nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,\n            &ctx->style.combo.button, sym, style->font);\n\n        /* draw symbol */\n        image.x = header.x + style->combo.content_padding.x;\n        image.y = header.y + style->combo.content_padding.y;\n        image.h = header.h - 2 * style->combo.content_padding.y;\n        image.w = image.h;\n        nk_draw_symbol(&win->buffer, symbol, image, text.background, symbol_color,\n            1.0f, style->font);\n\n        /* draw label */\n        text.padding = nk_vec2(0,0);\n        label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x;\n        label.y = header.y + style->combo.content_padding.y;\n        label.w = (button.x - style->combo.content_padding.x) - label.x;\n        label.h = header.h - 2 * style->combo.content_padding.y;\n        nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font);\n    }\n    return nk_combo_begin(ctx, win, size, is_clicked, header);\n}\nNK_API nk_bool\nnk_combo_begin_image(struct nk_context *ctx, struct nk_image img, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    const struct nk_input *in;\n\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    enum nk_widget_layout_states s;\n    const struct nk_style_item *background;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    s = nk_widget(&header, ctx);\n    if (s == NK_WIDGET_INVALID)\n        return 0;\n\n    in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;\n    if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))\n        is_clicked = nk_true;\n\n    /* draw combo box header background and border */\n    if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED)\n        background = &style->combo.active;\n    else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n        background = &style->combo.hover;\n    else background = &style->combo.normal;\n\n    switch (background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));\n            nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));\n            break;\n    }\n    {\n        struct nk_rect bounds = {0,0,0,0};\n        struct nk_rect content;\n        struct nk_rect button;\n        int draw_button_symbol;\n\n        enum nk_symbol_type sym;\n        if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n            sym = style->combo.sym_hover;\n        else if (is_clicked)\n            sym = style->combo.sym_active;\n        else sym = style->combo.sym_normal;\n\n        /* represents whether or not the combo's button symbol should be drawn */\n        draw_button_symbol = sym != NK_SYMBOL_NONE;\n\n        /* calculate button */\n        button.w = header.h - 2 * style->combo.button_padding.y;\n        button.x = (header.x + header.w - header.h) - style->combo.button_padding.y;\n        button.y = header.y + style->combo.button_padding.y;\n        button.h = button.w;\n\n        content.x = button.x + style->combo.button.padding.x;\n        content.y = button.y + style->combo.button.padding.y;\n        content.w = button.w - 2 * style->combo.button.padding.x;\n        content.h = button.h - 2 * style->combo.button.padding.y;\n\n        /* draw image */\n        bounds.h = header.h - 2 * style->combo.content_padding.y;\n        bounds.y = header.y + style->combo.content_padding.y;\n        bounds.x = header.x + style->combo.content_padding.x;\n        if (draw_button_symbol)\n            bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;\n        else\n            bounds.w = header.w - 2 * style->combo.content_padding.x;\n        nk_draw_image(&win->buffer, bounds, &img, nk_rgb_factor(nk_white, style->combo.color_factor));\n\n        /* draw open/close button */\n        if (draw_button_symbol)\n            nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state,\n                &ctx->style.combo.button, sym, style->font);\n    }\n    return nk_combo_begin(ctx, win, size, is_clicked, header);\n}\nNK_API nk_bool\nnk_combo_begin_image_text(struct nk_context *ctx, const char *selected, int len,\n    struct nk_image img, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    struct nk_input *in;\n\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    enum nk_widget_layout_states s;\n    const struct nk_style_item *background;\n    struct nk_text text;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    s = nk_widget(&header, ctx);\n    if (!s) return 0;\n\n    in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;\n    if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))\n        is_clicked = nk_true;\n\n    /* draw combo box header background and border */\n    if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->combo.active;\n        text.text = style->combo.label_active;\n    } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {\n        background = &style->combo.hover;\n        text.text = style->combo.label_hover;\n    } else {\n        background = &style->combo.normal;\n        text.text = style->combo.label_normal;\n    }\n\n    text.text = nk_rgb_factor(text.text, style->combo.color_factor);\n\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            text.background = background->data.color;\n            nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));\n            nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));\n            break;\n    }\n    {\n        struct nk_rect content;\n        struct nk_rect button;\n        struct nk_rect label;\n        struct nk_rect image;\n        int draw_button_symbol;\n\n        enum nk_symbol_type sym;\n        if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n            sym = style->combo.sym_hover;\n        else if (is_clicked)\n            sym = style->combo.sym_active;\n        else sym = style->combo.sym_normal;\n\n        /* represents whether or not the combo's button symbol should be drawn */\n        draw_button_symbol = sym != NK_SYMBOL_NONE;\n\n        /* calculate button */\n        button.w = header.h - 2 * style->combo.button_padding.y;\n        button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;\n        button.y = header.y + style->combo.button_padding.y;\n        button.h = button.w;\n\n        content.x = button.x + style->combo.button.padding.x;\n        content.y = button.y + style->combo.button.padding.y;\n        content.w = button.w - 2 * style->combo.button.padding.x;\n        content.h = button.h - 2 * style->combo.button.padding.y;\n        if (draw_button_symbol)\n            nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,\n                &ctx->style.combo.button, sym, style->font);\n\n        /* draw image */\n        image.x = header.x + style->combo.content_padding.x;\n        image.y = header.y + style->combo.content_padding.y;\n        image.h = header.h - 2 * style->combo.content_padding.y;\n        image.w = image.h;\n        nk_draw_image(&win->buffer, image, &img, nk_rgb_factor(nk_white, style->combo.color_factor));\n\n        /* draw label */\n        text.padding = nk_vec2(0,0);\n        label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x;\n        label.y = header.y + style->combo.content_padding.y;\n        label.h = header.h - 2 * style->combo.content_padding.y;\n        if (draw_button_symbol)\n            label.w = (button.x - style->combo.content_padding.x) - label.x;\n        else\n            label.w = (header.x + header.w - style->combo.content_padding.x) - label.x;\n        nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font);\n    }\n    return nk_combo_begin(ctx, win, size, is_clicked, header);\n}\nNK_API nk_bool\nnk_combo_begin_symbol_label(struct nk_context *ctx,\n    const char *selected, enum nk_symbol_type type, struct nk_vec2 size)\n{\n    return nk_combo_begin_symbol_text(ctx, selected, nk_strlen(selected), type, size);\n}\nNK_API nk_bool\nnk_combo_begin_image_label(struct nk_context *ctx,\n    const char *selected, struct nk_image img, struct nk_vec2 size)\n{\n    return nk_combo_begin_image_text(ctx, selected, nk_strlen(selected), img, size);\n}\nNK_API nk_bool\nnk_combo_item_text(struct nk_context *ctx, const char *text, int len,nk_flags align)\n{\n    return nk_contextual_item_text(ctx, text, len, align);\n}\nNK_API nk_bool\nnk_combo_item_label(struct nk_context *ctx, const char *label, nk_flags align)\n{\n    return nk_contextual_item_label(ctx, label, align);\n}\nNK_API nk_bool\nnk_combo_item_image_text(struct nk_context *ctx, struct nk_image img, const char *text,\n    int len, nk_flags alignment)\n{\n    return nk_contextual_item_image_text(ctx, img, text, len, alignment);\n}\nNK_API nk_bool\nnk_combo_item_image_label(struct nk_context *ctx, struct nk_image img,\n    const char *text, nk_flags alignment)\n{\n    return nk_contextual_item_image_label(ctx, img, text, alignment);\n}\nNK_API nk_bool\nnk_combo_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *text, int len, nk_flags alignment)\n{\n    return nk_contextual_item_symbol_text(ctx, sym, text, len, alignment);\n}\nNK_API nk_bool\nnk_combo_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *label, nk_flags alignment)\n{\n    return nk_contextual_item_symbol_label(ctx, sym, label, alignment);\n}\nNK_API void nk_combo_end(struct nk_context *ctx)\n{\n    nk_contextual_end(ctx);\n}\nNK_API void nk_combo_close(struct nk_context *ctx)\n{\n    nk_contextual_close(ctx);\n}\nNK_API int\nnk_combo(struct nk_context *ctx, const char *const *items, int count,\n    int selected, int item_height, struct nk_vec2 size)\n{\n    int i = 0;\n    int max_height;\n    struct nk_vec2 item_spacing;\n    struct nk_vec2 window_padding;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(items);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !items ||!count)\n        return selected;\n\n    item_spacing = ctx->style.window.spacing;\n    window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);\n    max_height = count * item_height + count * (int)item_spacing.y;\n    max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;\n    size.y = NK_MIN(size.y, (float)max_height);\n    if (nk_combo_begin_label(ctx, items[selected], size)) {\n        nk_layout_row_dynamic(ctx, (float)item_height, 1);\n        for (i = 0; i < count; ++i) {\n            if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))\n                selected = i;\n        }\n        nk_combo_end(ctx);\n    }\n    return selected;\n}\nNK_API int\nnk_combo_separator(struct nk_context *ctx, const char *items_separated_by_separator,\n    int separator, int selected, int count, int item_height, struct nk_vec2 size)\n{\n    int i;\n    int max_height;\n    struct nk_vec2 item_spacing;\n    struct nk_vec2 window_padding;\n    const char *current_item;\n    const char *iter;\n    int length = 0;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(items_separated_by_separator);\n    if (!ctx || !items_separated_by_separator)\n        return selected;\n\n    /* calculate popup window */\n    item_spacing = ctx->style.window.spacing;\n    window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);\n    max_height = count * item_height + count * (int)item_spacing.y;\n    max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;\n    size.y = NK_MIN(size.y, (float)max_height);\n\n    /* find selected item */\n    current_item = items_separated_by_separator;\n    for (i = 0; i < count; ++i) {\n        iter = current_item;\n        while (*iter && *iter != separator) iter++;\n        length = (int)(iter - current_item);\n        if (i == selected) break;\n        current_item = iter + 1;\n    }\n\n    if (nk_combo_begin_text(ctx, current_item, length, size)) {\n        current_item = items_separated_by_separator;\n        nk_layout_row_dynamic(ctx, (float)item_height, 1);\n        for (i = 0; i < count; ++i) {\n            iter = current_item;\n            while (*iter && *iter != separator) iter++;\n            length = (int)(iter - current_item);\n            if (nk_combo_item_text(ctx, current_item, length, NK_TEXT_LEFT))\n                selected = i;\n            current_item = current_item + length + 1;\n        }\n        nk_combo_end(ctx);\n    }\n    return selected;\n}\nNK_API int\nnk_combo_string(struct nk_context *ctx, const char *items_separated_by_zeros,\n    int selected, int count, int item_height, struct nk_vec2 size)\n{\n    return nk_combo_separator(ctx, items_separated_by_zeros, '\\0', selected, count, item_height, size);\n}\nNK_API int\nnk_combo_callback(struct nk_context *ctx, void(*item_getter)(void*, int, const char**),\n    void *userdata, int selected, int count, int item_height, struct nk_vec2 size)\n{\n    int i;\n    int max_height;\n    struct nk_vec2 item_spacing;\n    struct nk_vec2 window_padding;\n    const char *item;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(item_getter);\n    if (!ctx || !item_getter)\n        return selected;\n\n    /* calculate popup window */\n    item_spacing = ctx->style.window.spacing;\n    window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);\n    max_height = count * item_height + count * (int)item_spacing.y;\n    max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;\n    size.y = NK_MIN(size.y, (float)max_height);\n\n    item_getter(userdata, selected, &item);\n    if (nk_combo_begin_label(ctx, item, size)) {\n        nk_layout_row_dynamic(ctx, (float)item_height, 1);\n        for (i = 0; i < count; ++i) {\n            item_getter(userdata, i, &item);\n            if (nk_combo_item_label(ctx, item, NK_TEXT_LEFT))\n                selected = i;\n        }\n        nk_combo_end(ctx);\n    } return selected;\n}\nNK_API nk_bool\nnk_combobox(struct nk_context *ctx, const char *const *items, int count,\n    int *selected, int item_height, struct nk_vec2 size)\n{\n    int tmp = *selected;\n    *selected = nk_combo(ctx, items, count, *selected, item_height, size);\n    return tmp != *selected;\n}\nNK_API nk_bool\nnk_combobox_string(struct nk_context *ctx, const char *items_separated_by_zeros,\n    int *selected, int count, int item_height, struct nk_vec2 size)\n{\n    int tmp = *selected;\n    *selected = nk_combo_string(ctx, items_separated_by_zeros, *selected, count, item_height, size);\n    return tmp != *selected;\n}\nNK_API nk_bool\nnk_combobox_separator(struct nk_context *ctx, const char *items_separated_by_separator,\n    int separator, int *selected, int count, int item_height, struct nk_vec2 size)\n{\n    int tmp = *selected;\n    *selected = nk_combo_separator(ctx, items_separated_by_separator, separator,\n                                    *selected, count, item_height, size);\n    return tmp != *selected;\n}\nNK_API nk_bool\nnk_combobox_callback(struct nk_context *ctx,\n    void(*item_getter)(void* data, int id, const char **out_text),\n    void *userdata, int *selected, int count, int item_height, struct nk_vec2 size)\n{\n    int tmp = *selected;\n    *selected = nk_combo_callback(ctx, item_getter, userdata,  *selected, count, item_height, size);\n    return tmp != *selected;\n}\n\n\n\n\n/* ===============================================================\n *\n *                              TOOLTIP\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_tooltip_begin(struct nk_context *ctx, float width)\n{\n    NK_ASSERT(ctx);\n    return nk_tooltip_begin_offset(ctx, width, ctx->style.window.tooltip_origin, ctx->style.window.tooltip_offset);\n}\n\nNK_API nk_bool\nnk_tooltip_begin_offset(struct nk_context *ctx, float width, enum nk_tooltip_pos position, struct nk_vec2 offset)\n{\n    int x,y,w,h;\n    struct nk_window *win;\n    const struct nk_input *in;\n    struct nk_rect bounds;\n    int ret;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    /* make sure that no nonblocking popup is currently active */\n    win = ctx->current;\n    in = &ctx->input;\n    if (win->popup.win && ((int)win->popup.type & (int)NK_PANEL_SET_NONBLOCK))\n        return 0;\n\n    w = nk_iceilf(width);\n    h = NK_MAX(win->layout->row.min_height, ctx->style.font->height+2*ctx->style.window.padding.y);\n\n    /* Default origin is top left, plus user offset */\n    x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x + offset.x;\n    y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y + offset.y;\n\n    /* Adjust origin based on enum */\n    switch (position) {\n    case NK_TOP_LEFT:\n        /* no change */\n        break;\n    case NK_TOP_CENTER:\n        x -= w/2;\n        break;\n    case NK_TOP_RIGHT:\n        x -= w;\n        break;\n\n    case NK_MIDDLE_LEFT:\n        y -= h/2;\n        break;\n    case NK_MIDDLE_CENTER:\n        x -= w/2;\n        y -= h/2;\n        break;\n    case NK_MIDDLE_RIGHT:\n        x -= w;\n        y -= h/2;\n        break;\n\n    case NK_BOTTOM_LEFT:\n        y -= h;\n        break;\n    case NK_BOTTOM_CENTER:\n        x -= w/2;\n        y -= h;\n        break;\n    case NK_BOTTOM_RIGHT:\n        x -= w;\n        y -= h;\n        break;\n    default:\n        NK_ASSERT(0 && \"Invalid tooltip position\");\n    }\n\n    bounds.x = (float)x;\n    bounds.y = (float)y;\n    bounds.w = (float)w;\n    bounds.h = (float)nk_iceilf(nk_null_rect.h);\n\n    ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC,\n        \"__##Tooltip##__\", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds);\n    if (ret) win->layout->flags &= ~(nk_flags)NK_WINDOW_ROM;\n    win->popup.type = NK_PANEL_TOOLTIP;\n    ctx->current->layout->type = NK_PANEL_TOOLTIP;\n    return ret;\n}\n\nNK_API void\nnk_tooltip_end(struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return;\n    ctx->current->seq--;\n    nk_popup_close(ctx);\n    nk_popup_end(ctx);\n}\n\nNK_API void\nnk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset)\n{\n    const struct nk_style *style;\n    struct nk_vec2 padding;\n\n    int text_len;\n    float text_width;\n    float text_height;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    NK_ASSERT(text);\n    if (!ctx || !ctx->current || !ctx->current->layout || !text)\n        return;\n\n    /* fetch configuration data */\n    style = &ctx->style;\n    padding = style->window.padding;\n\n    /* calculate size of the text and tooltip */\n    text_len = nk_strlen(text);\n    text_width = style->font->width(style->font->userdata,\n                    style->font->height, text, text_len);\n    text_width += (4 * padding.x);\n    text_height = (style->font->height + 2 * padding.y);\n\n    /* execute tooltip and fill with text */\n    if (nk_tooltip_begin_offset(ctx, (float)text_width, position, offset)) {\n        nk_layout_row_dynamic(ctx, (float)text_height, 1);\n        nk_text(ctx, text, text_len, NK_TEXT_LEFT);\n        nk_tooltip_end(ctx);\n    }\n}\n\nNK_API void\nnk_tooltip(struct nk_context *ctx, const char *text)\n{\n    NK_ASSERT(ctx);\n    nk_tooltip_offset(ctx, text, ctx->style.window.tooltip_origin, ctx->style.window.tooltip_offset);\n}\n#ifdef NK_INCLUDE_STANDARD_VARARGS\nNK_API void\nnk_tooltipf_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    nk_tooltipfv_offset(ctx, position, offset, fmt, args);\n    va_end(args);\n}\nNK_API void\nnk_tooltipf(struct nk_context *ctx, const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    nk_tooltipfv(ctx, fmt, args);\n    va_end(args);\n}\nNK_API void\nnk_tooltipfv_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, va_list args)\n{\n    char buf[256];\n    nk_strfmt(buf, NK_LEN(buf), fmt, args);\n    nk_tooltip_offset(ctx, buf, position, offset);\n}\nNK_API void\nnk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args)\n{\n    char buf[256];\n    nk_strfmt(buf, NK_LEN(buf), fmt, args);\n    nk_tooltip(ctx, buf);\n}\n#endif\n\n\n\n#endif /* NK_IMPLEMENTATION */\n\n/*\n/// ## License\n/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none\n///    ------------------------------------------------------------------------------\n///    This software is available under 2 licenses -- choose whichever you prefer.\n///    ------------------------------------------------------------------------------\n///    ALTERNATIVE A - MIT License\n///    Copyright (c) 2016-2018 Micha Mettke\n///    Permission is hereby granted, free of charge, to any person obtaining a copy of\n///    this software and associated documentation files (the \"Software\"), to deal in\n///    the Software without restriction, including without limitation the rights to\n///    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\n///    of the Software, and to permit persons to whom the Software is furnished to do\n///    so, subject to the following conditions:\n///    The above copyright notice and this permission notice shall be included in all\n///    copies or substantial portions of the Software.\n///    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n///    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n///    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n///    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n///    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n///    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n///    SOFTWARE.\n///    ------------------------------------------------------------------------------\n///    ALTERNATIVE B - Public Domain (www.unlicense.org)\n///    This is free and unencumbered software released into the public domain.\n///    Anyone is free to copy, modify, publish, use, compile, sell, or distribute this\n///    software, either in source code form or as a compiled binary, for any purpose,\n///    commercial or non-commercial, and by any means.\n///    In jurisdictions that recognize copyright laws, the author or authors of this\n///    software dedicate any and all copyright interest in the software to the public\n///    domain. We make this dedication for the benefit of the public at large and to\n///    the detriment of our heirs and successors. We intend this dedication to be an\n///    overt act of relinquishment in perpetuity of all present and future rights to\n///    this software under copyright law.\n///    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n///    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n///    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n///    AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n///    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n///    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n///    ------------------------------------------------------------------------------\n/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n/// ## Changelog\n/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none\n/// [date] ([x.y.z]) - [description]\n/// - [date]: date on which the change has been pushed\n/// - [x.y.z]: Version string, represented in Semantic Versioning format\n///   - [x]: Major version with API and library breaking changes\n///   - [y]: Minor version with non-breaking API and library changes\n///   - [z]: Patch version with no direct changes to the API\n///\n/// - 2026/01/31 (4.13.2) - Fix: replace incorrect static asserts for size(nk_bool)\n/// - 2026/01/26 (4.13.1) - Fix: nk_do_property now uses NK_STRTOD via macro\n///                       - Fix: failure to build from source, due to\n///                         nuklear_math/util.c not declaring some functions\n///                       - Fix: guard nk_strtod implementation with preprocessor\n///                       - Fix: nuklear_sdl3_renderer now provides NK_DTOA\n///                       - Fix: guard nk_pow, nk_ifloord, nk_log10 with preprocessor\n/// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active'\n///                         Add new updated demo: sdl3_renderer\n/// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default,\n///                         instead of silently failing when no x-axis alignment is provided,\n///                         and refactor this function to keep the code style consistent\n/// - 2025/09/12 (4.12.8) - Fix nk_window_is_hovered to use current window flags\n                          - Fix nk_utf_decode length check (allow len == NK_UTF_SIZE)\n/// - 2025/04/28 (4.12.8) - Allow switching between TEXT_INSERT and TEXT_REPLACE modes directly\n/// - 2025/04/06 (4.12.7) - Fix text input navigation and mouse scrolling\n/// - 2025/03/29 (4.12.6) - Fix unitialized data in nk_input_char\n/// - 2025/03/05 (4.12.5) - Fix scrolling knob also scrolling parent window, remove dead code\n/// - 2024/12/11 (4.12.4) - Fix array subscript [0, 0] is outside array bounds of ‘char[1]’\n/// - 2024/12/11 (4.12.3) - Fix border color for property widgets\n/// - 2024/11/20 (4.12.2) - Fix int/float type conversion warnings in `nk_roundf`\n/// - 2024/03/07 (4.12.1) - Fix bitwise operations warnings in C++20\n/// - 2023/11/26 (4.12.0) - Added an alignment option to checkboxes and radio buttons.\n/// - 2023/10/11 (4.11.0) - Added nk_widget_disable_begin() and nk_widget_disable_end()\n/// - 2022/12/23 (4.10.6) - Fix incorrect glyph index in nk_font_bake()\n/// - 2022/12/17 (4.10.5) - Fix nk_font_bake_pack() using TTC font offset incorrectly\n/// - 2022/10/24 (4.10.4) - Fix nk_str_{append,insert}_str_utf8 always returning 0\n/// - 2022/09/03 (4.10.3) - Renamed the `null` texture variable to `tex_null`\n/// - 2022/08/01 (4.10.2) - Fix Apple Silicon with incorrect NK_SITE_TYPE and NK_POINTER_TYPE\n/// - 2022/08/01 (4.10.1) - Fix cursor jumping back to beginning of text when typing more than\n///                         nk_edit_xxx limit\n/// - 2022/05/27 (4.10.0) - Add nk_input_has_mouse_click_in_button_rect() to fix window move bug\n/// - 2022/04/19 (4.9.8)  - Added nk_rule_horizontal() widget\n/// - 2022/04/18 (4.9.7)  - Change button behavior when NK_BUTTON_TRIGGER_ON_RELEASE is defined to\n///                         only trigger when the mouse position was inside the same button on down\n/// - 2022/02/03 (4.9.6)  - Allow overriding the NK_INV_SQRT function, similar to NK_SIN and NK_COS\n/// - 2021/12/22 (4.9.5)  - Revert layout bounds not accounting for padding due to regressions\n/// - 2021/12/22 (4.9.4)  - Fix checking hovering when window is minimized\n/// - 2021/12/22 (4.09.3) - Fix layout bounds not accounting for padding\n/// - 2021/12/19 (4.09.2) - Update to stb_rect_pack.h v1.01 and stb_truetype.h v1.26\n/// - 2021/12/16 (4.09.1) - Fix the majority of GCC warnings\n/// - 2021/10/16 (4.09.0) - Added nk_spacer() widget\n/// - 2021/09/22 (4.08.6) - Fix \"may be used uninitialized\" warnings in nk_widget\n/// - 2021/09/22 (4.08.5) - GCC __builtin_offsetof only exists in version 4 and later\n/// - 2021/09/15 (4.08.4) - Fix \"'num_len' may be used uninitialized\" in nk_do_property\n/// - 2021/09/15 (4.08.3) - Fix \"Templates cannot be declared to have 'C' Linkage\"\n/// - 2021/09/08 (4.08.2) - Fix warnings in C89 builds\n/// - 2021/09/08 (4.08.1) - Use compiler builtins for NK_OFFSETOF when possible\n/// - 2021/08/17 (4.08.0) - Implemented 9-slice scaling support for widget styles\n/// - 2021/08/16 (4.07.5) - Replace usage of memset in nk_font_atlas_bake with NK_MEMSET\n/// - 2021/08/15 (4.07.4) - Fix conversion and sign conversion warnings\n/// - 2021/08/08 (4.07.3) - Fix crash when baking merged fonts\n/// - 2021/08/08 (4.07.2) - Fix Multiline Edit wrong offset\n/// - 2021/03/17 (4.07.1) - Fix warning about unused parameter\n/// - 2021/03/17 (4.07.0) - Fix nk_property hover bug\n/// - 2021/03/15 (4.06.4) - Change nk_propertyi back to int\n/// - 2021/03/15 (4.06.3) - Update documentation for functions that now return nk_bool\n/// - 2020/12/19 (4.06.2) - Fix additional C++ style comments which are not allowed in ISO C90.\n/// - 2020/10/11 (4.06.1) - Fix C++ style comments which are not allowed in ISO C90.\n/// - 2020/10/07 (4.06.0) - Fix nk_combo return type wrongly changed to nk_bool\n/// - 2020/09/05 (4.05.0) - Use the nk_font_atlas allocator for stb_truetype memory management.\n/// - 2020/09/04 (4.04.1) - Replace every boolean int by nk_bool\n/// - 2020/09/04 (4.04.0) - Add nk_bool with NK_INCLUDE_STANDARD_BOOL\n/// - 2020/06/13 (4.03.1) - Fix nk_pool allocation sizes.\n/// - 2020/06/04 (4.03.0) - Made nk_combo header symbols optional.\n/// - 2020/05/27 (4.02.5) - Fix nk_do_edit: Keep scroll position when re-activating edit widget.\n/// - 2020/05/09 (4.02.4) - Fix nk_menubar height calculation bug\n/// - 2020/05/08 (4.02.3) - Fix missing stdarg.h with NK_INCLUDE_STANDARD_VARARGS\n/// - 2020/04/30 (4.02.2) - Fix nk_edit border drawing bug\n/// - 2020/04/09 (4.02.1) - Removed unused nk_sqrt function to fix compiler warnings\n///                       - Fixed compiler warnings if you bring your own methods for\n///                        nk_cos/nk_sin/nk_strtod/nk_memset/nk_memcopy/nk_dtoa\n/// - 2020/04/06 (4.01.10) - Fix bug: Do not use pool before checking for NULL\n/// - 2020/03/22 (4.01.9) - Fix bug where layout state wasn't restored correctly after\n///                        popping a tree.\n/// - 2020/03/11 (4.01.8) - Fix bug where padding is subtracted from widget\n/// - 2020/03/06 (4.01.7) - Fix bug where width padding was applied twice\n/// - 2020/02/06 (4.01.6) - Update stb_truetype.h and stb_rect_pack.h and separate them\n/// - 2019/12/10 (4.01.5) - Fix off-by-one error in NK_INTERSECT\n/// - 2019/10/09 (4.01.4) - Fix bug for autoscrolling in nk_do_edit\n/// - 2019/09/20 (4.01.3) - Fixed a bug wherein combobox cannot be closed by clicking the header\n///                        when NK_BUTTON_TRIGGER_ON_RELEASE is defined.\n/// - 2019/09/10 (4.01.2) - Fixed the nk_cos function, which deviated significantly.\n/// - 2019/09/08 (4.01.1) - Fixed a bug wherein re-baking of fonts caused a segmentation\n///                        fault due to dst_font->glyph_count not being zeroed on subsequent\n///                        bakes of the same set of fonts.\n/// - 2019/06/23 (4.01.0) - Added nk_***_get_scroll and nk_***_set_scroll for groups, windows, and popups.\n/// - 2019/06/12 (4.00.3) - Fix panel background drawing bug.\n/// - 2018/10/31 (4.00.2) - Added NK_KEYSTATE_BASED_INPUT to \"fix\" state based backends\n///                        like GLFW without breaking key repeat behavior on event based.\n/// - 2018/04/01 (4.00.1) - Fixed calling `nk_convert` multiple time per single frame.\n/// - 2018/04/01 (4.00.0) - BREAKING CHANGE: nk_draw_list_clear no longer tries to\n///                        clear provided buffers. So make sure to either free\n///                        or clear each passed buffer after calling nk_convert.\n/// - 2018/02/23 (3.00.6) - Fixed slider dragging behavior.\n/// - 2018/01/31 (3.00.5) - Fixed overcalculation of cursor data in font baking process.\n/// - 2018/01/31 (3.00.4) - Removed name collision with stb_truetype.\n/// - 2018/01/28 (3.00.3) - Fixed panel window border drawing bug.\n/// - 2018/01/12 (3.00.2) - Added `nk_group_begin_titled` for separated group identifier and title.\n/// - 2018/01/07 (3.00.1) - Started to change documentation style.\n/// - 2018/01/05 (3.00.0) - BREAKING CHANGE: The previous color picker API was broken\n///                        because of conversions between float and byte color representation.\n///                        Color pickers now use floating point values to represent\n///                        HSV values. To get back the old behavior I added some additional\n///                        color conversion functions to cast between nk_color and\n///                        nk_colorf.\n/// - 2017/12/23 (2.00.7) - Fixed small warning.\n/// - 2017/12/23 (2.00.7) - Fixed `nk_edit_buffer` behavior if activated to allow input.\n/// - 2017/12/23 (2.00.7) - Fixed modifyable progressbar dragging visuals and input behavior.\n/// - 2017/12/04 (2.00.6) - Added formatted string tooltip widget.\n/// - 2017/11/18 (2.00.5) - Fixed window becoming hidden with flag `NK_WINDOW_NO_INPUT`.\n/// - 2017/11/15 (2.00.4) - Fixed font merging.\n/// - 2017/11/07 (2.00.3) - Fixed window size and position modifier functions.\n/// - 2017/09/14 (2.00.2) - Fixed `nk_edit_buffer` and `nk_edit_focus` behavior.\n/// - 2017/09/14 (2.00.1) - Fixed window closing behavior.\n/// - 2017/09/14 (2.00.0) - BREAKING CHANGE: Modifying window position and size functions now\n///                        require the name of the window and must happen outside the window\n///                        building process (between function call nk_begin and nk_end).\n/// - 2017/09/11 (1.40.9) - Fixed window background flag if background window is declared last.\n/// - 2017/08/27 (1.40.8) - Fixed `nk_item_is_any_active` for hidden windows.\n/// - 2017/08/27 (1.40.7) - Fixed window background flag.\n/// - 2017/07/07 (1.40.6) - Fixed missing clipping rect check for hovering/clicked\n///                        query for widgets.\n/// - 2017/07/07 (1.40.5) - Fixed drawing bug for vertex output for lines and stroked\n///                        and filled rectangles.\n/// - 2017/07/07 (1.40.4) - Fixed bug in nk_convert trying to add windows that are in\n///                        process of being destroyed.\n/// - 2017/07/07 (1.40.3) - Fixed table internal bug caused by storing table size in\n///                        window instead of directly in table.\n/// - 2017/06/30 (1.40.2) - Removed unneeded semicolon in C++ NK_ALIGNOF macro.\n/// - 2017/06/30 (1.40.1) - Fixed drawing lines smaller or equal zero.\n/// - 2017/06/08 (1.40.0) - Removed the breaking part of last commit. Auto layout now only\n///                        comes in effect if you pass in zero was row height argument.\n/// - 2017/06/08 (1.40.0) - BREAKING CHANGE: while not directly API breaking it will change\n///                        how layouting works. From now there will be an internal minimum\n///                        row height derived from font height. If you need a row smaller than\n///                        that you can directly set it by `nk_layout_set_min_row_height` and\n///                        reset the value back by calling `nk_layout_reset_min_row_height.\n/// - 2017/06/08 (1.39.1) - Fixed property text edit handling bug caused by past `nk_widget` fix.\n/// - 2017/06/08 (1.39.0) - Added function to retrieve window space without calling a `nk_layout_xxx` function.\n/// - 2017/06/06 (1.38.5) - Fixed `nk_convert` return flag for command buffer.\n/// - 2017/05/23 (1.38.4) - Fixed activation behavior for widgets partially clipped.\n/// - 2017/05/10 (1.38.3) - Fixed wrong min window size mouse scaling over boundaries.\n/// - 2017/05/09 (1.38.2) - Fixed vertical scrollbar drawing with not enough space.\n/// - 2017/05/09 (1.38.1) - Fixed scaler dragging behavior if window size hits minimum size.\n/// - 2017/05/06 (1.38.0) - Added platform double-click support.\n/// - 2017/04/20 (1.37.1) - Fixed key repeat found inside glfw demo backends.\n/// - 2017/04/20 (1.37.0) - Extended properties with selection and clipboard support.\n/// - 2017/04/20 (1.36.2) - Fixed #405 overlapping rows with zero padding and spacing.\n/// - 2017/04/09 (1.36.1) - Fixed #403 with another widget float error.\n/// - 2017/04/09 (1.36.0) - Added window `NK_WINDOW_NO_INPUT` and `NK_WINDOW_NOT_INTERACTIVE` flags.\n/// - 2017/04/09 (1.35.3) - Fixed buffer heap corruption.\n/// - 2017/03/25 (1.35.2) - Fixed popup overlapping for `NK_WINDOW_BACKGROUND` windows.\n/// - 2017/03/25 (1.35.1) - Fixed windows closing behavior.\n/// - 2017/03/18 (1.35.0) - Added horizontal scroll requested in #377.\n/// - 2017/03/18 (1.34.3) - Fixed long window header titles.\n/// - 2017/03/04 (1.34.2) - Fixed text edit filtering.\n/// - 2017/03/04 (1.34.1) - Fixed group closable flag.\n/// - 2017/02/25 (1.34.0) - Added custom draw command for better language binding support.\n/// - 2017/01/24 (1.33.0) - Added programmatic way to remove edit focus.\n/// - 2017/01/24 (1.32.3) - Fixed wrong define for basic type definitions for windows.\n/// - 2017/01/21 (1.32.2) - Fixed input capture from hidden or closed windows.\n/// - 2017/01/21 (1.32.1) - Fixed slider behavior and drawing.\n/// - 2017/01/13 (1.32.0) - Added flag to put scaler into the bottom left corner.\n/// - 2017/01/13 (1.31.0) - Added additional row layouting method to combine both\n///                        dynamic and static widgets.\n/// - 2016/12/31 (1.30.0) - Extended scrollbar offset from 16-bit to 32-bit.\n/// - 2016/12/31 (1.29.2) - Fixed closing window bug of minimized windows.\n/// - 2016/12/03 (1.29.1) - Fixed wrapped text with no separator and C89 error.\n/// - 2016/12/03 (1.29.0) - Changed text wrapping to process words not characters.\n/// - 2016/11/22 (1.28.6) - Fixed window minimized closing bug.\n/// - 2016/11/19 (1.28.5) - Fixed abstract combo box closing behavior.\n/// - 2016/11/19 (1.28.4) - Fixed tooltip flickering.\n/// - 2016/11/19 (1.28.3) - Fixed memory leak caused by popup repeated closing.\n/// - 2016/11/18 (1.28.2) - Fixed memory leak caused by popup panel allocation.\n/// - 2016/11/10 (1.28.1) - Fixed some warnings and C++ error.\n/// - 2016/11/10 (1.28.0) - Added additional `nk_button` versions which allows to directly\n///                        pass in a style struct to change buttons visual.\n/// - 2016/11/10 (1.27.0) - Added additional `nk_tree` versions to support external state\n///                        storage. Just like last the `nk_group` commit the main\n///                        advantage is that you optionally can minimize nuklears runtime\n///                        memory consumption or handle hash collisions.\n/// - 2016/11/09 (1.26.0) - Added additional `nk_group` version to support external scrollbar\n///                        offset storage. Main advantage is that you can externalize\n///                        the memory management for the offset. It could also be helpful\n///                        if you have a hash collision in `nk_group_begin` but really\n///                        want the name. In addition I added `nk_list_view` which allows\n///                        to draw big lists inside a group without actually having to\n///                        commit the whole list to nuklear (issue #269).\n/// - 2016/10/30 (1.25.1) - Fixed clipping rectangle bug inside `nk_draw_list`.\n/// - 2016/10/29 (1.25.0) - Pulled `nk_panel` memory management into nuklear and out of\n///                        the hands of the user. From now on users don't have to care\n///                        about panels unless they care about some information. If you\n///                        still need the panel just call `nk_window_get_panel`.\n/// - 2016/10/21 (1.24.0) - Changed widget border drawing to stroked rectangle from filled\n///                        rectangle for less overdraw and widget background transparency.\n/// - 2016/10/18 (1.23.0) - Added `nk_edit_focus` for manually edit widget focus control.\n/// - 2016/09/29 (1.22.7) - Fixed deduction of basic type in non `<stdint.h>` compilation.\n/// - 2016/09/29 (1.22.6) - Fixed edit widget UTF-8 text cursor drawing bug.\n/// - 2016/09/28 (1.22.5) - Fixed edit widget UTF-8 text appending/inserting/removing.\n/// - 2016/09/28 (1.22.4) - Fixed drawing bug inside edit widgets which offset all text\n///                        text in every edit widget if one of them is scrolled.\n/// - 2016/09/28 (1.22.3) - Fixed small bug in edit widgets if not active. The wrong\n///                        text length is passed. It should have been in bytes but\n///                        was passed as glyphs.\n/// - 2016/09/20 (1.22.2) - Fixed color button size calculation.\n/// - 2016/09/20 (1.22.1) - Fixed some `nk_vsnprintf` behavior bugs and removed `<stdio.h>`\n///                        again from `NK_INCLUDE_STANDARD_VARARGS`.\n/// - 2016/09/18 (1.22.0) - C89 does not support vsnprintf only C99 and newer as well\n///                        as C++11 and newer. In addition to use vsnprintf you have\n///                        to include <stdio.h>. So just defining `NK_INCLUDE_STD_VAR_ARGS`\n///                        is not enough. That behavior is now fixed. By default if\n///                        both varargs as well as stdio is selected I try to use\n///                        vsnprintf if not possible I will revert to vsprintf. If\n///                        varargs but not stdio was defined I will use my own function.\n/// - 2016/09/15 (1.21.2) - Fixed panel `close` behavior for deeper panel levels.\n/// - 2016/09/15 (1.21.1) - Fixed C++ errors and wrong argument to `nk_panel_get_xxxx`.\n/// - 2016/09/13 (1.21.0) - !BREAKING! Fixed nonblocking popup behavior in menu, combo,\n///                        and contextual which prevented closing in y-direction if\n///                        popup did not reach max height.\n///                        In addition the height parameter was changed into vec2\n///                        for width and height to have more control over the popup size.\n/// - 2016/09/13 (1.20.3) - Cleaned up and extended type selection.\n/// - 2016/09/13 (1.20.2) - Fixed slider behavior hopefully for the last time. This time\n///                        all calculation are correct so no more hackery.\n/// - 2016/09/13 (1.20.1) - Internal change to divide window/panel flags into panel flags and types.\n///                        Suprisinly spend years in C and still happened to confuse types\n///                        with flags. Probably something to take note.\n/// - 2016/09/08 (1.20.0) - Added additional helper function to make it easier to just\n///                        take the produced buffers from `nk_convert` and unplug the\n///                        iteration process from `nk_context`. So now you can\n///                        just use the vertex,element and command buffer + two pointer\n///                        inside the command buffer retrieved by calls `nk__draw_begin`\n///                        and `nk__draw_end` and macro `nk_draw_foreach_bounded`.\n/// - 2016/09/08 (1.19.0) - Added additional asserts to make sure every `nk_xxx_begin` call\n///                        for windows, popups, combobox, menu and contextual is guarded by\n///                        `if` condition and does not produce false drawing output.\n/// - 2016/09/08 (1.18.0) - Changed confusing name for `NK_SYMBOL_RECT_FILLED`, `NK_SYMBOL_RECT`\n///                        to hopefully easier to understand `NK_SYMBOL_RECT_FILLED` and\n///                        `NK_SYMBOL_RECT_OUTLINE`.\n/// - 2016/09/08 (1.17.0) - Changed confusing name for `NK_SYMBOL_CIRLCE_FILLED`, `NK_SYMBOL_CIRCLE`\n///                        to hopefully easier to understand `NK_SYMBOL_CIRCLE_FILLED` and\n///                        `NK_SYMBOL_CIRCLE_OUTLINE`.\n/// - 2016/09/08 (1.16.0) - Added additional checks to select correct types if `NK_INCLUDE_FIXED_TYPES`\n///                        is not defined by supporting the biggest compiler GCC, clang and MSVC.\n/// - 2016/09/07 (1.15.3) - Fixed `NK_INCLUDE_COMMAND_USERDATA` define to not cause an error.\n/// - 2016/09/04 (1.15.2) - Fixed wrong combobox height calculation.\n/// - 2016/09/03 (1.15.1) - Fixed gaps inside combo boxes in OpenGL.\n/// - 2016/09/02 (1.15.0) - Changed nuklear to not have any default vertex layout and\n///                        instead made it user provided. The range of types to convert\n///                        to is quite limited at the moment, but I would be more than\n///                        happy to accept PRs to add additional.\n/// - 2016/08/30 (1.14.2) - Removed unused variables.\n/// - 2016/08/30 (1.14.1) - Fixed C++ build errors.\n/// - 2016/08/30 (1.14.0) - Removed mouse dragging from SDL demo since it does not work correctly.\n/// - 2016/08/30 (1.13.4) - Tweaked some default styling variables.\n/// - 2016/08/30 (1.13.3) - Hopefully fixed drawing bug in slider, in general I would\n///                        refrain from using slider with a big number of steps.\n/// - 2016/08/30 (1.13.2) - Fixed close and minimize button which would fire even if the\n///                        window was in Read Only Mode.\n/// - 2016/08/30 (1.13.1) - Fixed popup panel padding handling which was previously just\n///                        a hack for combo box and menu.\n/// - 2016/08/30 (1.13.0) - Removed `NK_WINDOW_DYNAMIC` flag from public API since\n///                        it is bugged and causes issues in window selection.\n/// - 2016/08/30 (1.12.0) - Removed scaler size. The size of the scaler is now\n///                        determined by the scrollbar size.\n/// - 2016/08/30 (1.11.2) - Fixed some drawing bugs caused by changes from 1.11.0.\n/// - 2016/08/30 (1.11.1) - Fixed overlapping minimized window selection.\n/// - 2016/08/30 (1.11.0) - Removed some internal complexity and overly complex code\n///                        handling panel padding and panel border.\n/// - 2016/08/29 (1.10.0) - Added additional height parameter to `nk_combobox_xxx`.\n/// - 2016/08/29 (1.10.0) - Fixed drawing bug in dynamic popups.\n/// - 2016/08/29 (1.10.0) - Added experimental mouse scrolling to popups, menus and comboboxes.\n/// - 2016/08/26 (1.10.0) - Added window name string prepresentation to account for\n///                        hash collisions. Currently limited to `NK_WINDOW_MAX_NAME`\n///                        which in term can be redefined if not big enough.\n/// - 2016/08/26 (1.10.0) - Added stacks for temporary style/UI changes in code.\n/// - 2016/08/25 (1.10.0) - Changed `nk_input_is_key_pressed` and 'nk_input_is_key_released'\n///                        to account for key press and release happening in one frame.\n/// - 2016/08/25 (1.10.0) - Added additional nk_edit flag to directly jump to the end on activate.\n/// - 2016/08/17 (1.09.6) - Removed invalid check for value zero in `nk_propertyx`.\n/// - 2016/08/16 (1.09.5) - Fixed ROM mode for deeper levels of popup windows parents.\n/// - 2016/08/15 (1.09.4) - Editbox are now still active if enter was pressed with flag\n///                        `NK_EDIT_SIG_ENTER`. Main reasoning is to be able to keep\n///                        typing after committing.\n/// - 2016/08/15 (1.09.4) - Removed redundant code.\n/// - 2016/08/15 (1.09.4) - Fixed negative numbers in `nk_strtoi` and remove unused variable.\n/// - 2016/08/15 (1.09.3) - Fixed `NK_WINDOW_BACKGROUND` flag behavior to select a background\n///                        window only as selected by hovering and not by clicking.\n/// - 2016/08/14 (1.09.2) - Fixed a bug in font atlas which caused wrong loading\n///                        of glyphs for font with multiple ranges.\n/// - 2016/08/12 (1.09.1) - Added additional function to check if window is currently\n///                        hidden and therefore not visible.\n/// - 2016/08/12 (1.09.1) - nk_window_is_closed now queries the correct flag `NK_WINDOW_CLOSED`\n///                        instead of the old flag `NK_WINDOW_HIDDEN`.\n/// - 2016/08/09 (1.09.0) - Added additional double version to nk_property and changed\n///                        the underlying implementation to not cast to float and instead\n///                        work directly on the given values.\n/// - 2016/08/09 (1.08.0) - Added additional define to overwrite library internal\n///                        floating pointer number to string conversion for additional\n///                        precision.\n/// - 2016/08/09 (1.08.0) - Added additional define to overwrite library internal\n///                        string to floating point number conversion for additional\n///                        precision.\n/// - 2016/08/08 (1.07.2) - Fixed compiling error without define `NK_INCLUDE_FIXED_TYPE`.\n/// - 2016/08/08 (1.07.1) - Fixed possible floating point error inside `nk_widget` leading\n///                        to wrong widget width calculation which results in widgets falsely\n///                        becoming tagged as not inside window and cannot be accessed.\n/// - 2016/08/08 (1.07.0) - Nuklear now differentiates between hiding a window (NK_WINDOW_HIDDEN) and\n///                        closing a window (NK_WINDOW_CLOSED). A window can be hidden/shown\n///                        by using `nk_window_show` and closed by either clicking the close\n///                        icon in a window or by calling `nk_window_close`. Only closed\n///                        windows get removed at the end of the frame while hidden windows\n///                        remain.\n/// - 2016/08/08 (1.06.0) - Added `nk_edit_string_zero_terminated` as a second option to\n///                        `nk_edit_string` which takes, edits and outputs a '\\0' terminated string.\n/// - 2016/08/08 (1.05.4) - Fixed scrollbar auto hiding behavior.\n/// - 2016/08/08 (1.05.3) - Fixed wrong panel padding selection in `nk_layout_widget_space`.\n/// - 2016/08/07 (1.05.2) - Fixed old bug in dynamic immediate mode layout API, calculating\n///                        wrong item spacing and panel width.\n/// - 2016/08/07 (1.05.1) - Hopefully finally fixed combobox popup drawing bug.\n/// - 2016/08/07 (1.05.0) - Split varargs away from `NK_INCLUDE_STANDARD_IO` into own\n///                        define `NK_INCLUDE_STANDARD_VARARGS` to allow more fine\n///                        grained controlled over library includes.\n/// - 2016/08/06 (1.04.5) - Changed memset calls to `NK_MEMSET`.\n/// - 2016/08/04 (1.04.4) - Fixed fast window scaling behavior.\n/// - 2016/08/04 (1.04.3) - Fixed window scaling, movement bug which appears if you\n///                        move/scale a window and another window is behind it.\n///                        If you are fast enough then the window behind gets activated\n///                        and the operation is blocked. I now require activating\n///                        by hovering only if mouse is not pressed.\n/// - 2016/08/04 (1.04.2) - Fixed changing fonts.\n/// - 2016/08/03 (1.04.1) - Fixed `NK_WINDOW_BACKGROUND` behavior.\n/// - 2016/08/03 (1.04.0) - Added color parameter to `nk_draw_image`.\n/// - 2016/08/03 (1.04.0) - Added additional window padding style attributes for\n///                        sub windows (combo, menu, ...).\n/// - 2016/08/03 (1.04.0) - Added functions to show/hide software cursor.\n/// - 2016/08/03 (1.04.0) - Added `NK_WINDOW_BACKGROUND` flag to force a window\n///                        to be always in the background of the screen.\n/// - 2016/08/03 (1.03.2) - Removed invalid assert macro for NK_RGB color picker.\n/// - 2016/08/01 (1.03.1) - Added helper macros into header include guard.\n/// - 2016/07/29 (1.03.0) - Moved the window/table pool into the header part to\n///                        simplify memory management by removing the need to\n///                        allocate the pool.\n/// - 2016/07/29 (1.02.0) - Added auto scrollbar hiding window flag which if enabled\n///                        will hide the window scrollbar after NK_SCROLLBAR_HIDING_TIMEOUT\n///                        seconds without window interaction. To make it work\n///                        you have to also set a delta time inside the `nk_context`.\n/// - 2016/07/25 (1.01.1) - Fixed small panel and panel border drawing bugs.\n/// - 2016/07/15 (1.01.0) - Added software cursor to `nk_style` and `nk_context`.\n/// - 2016/07/15 (1.01.0) - Added const correctness to `nk_buffer_push' data argument.\n/// - 2016/07/15 (1.01.0) - Removed internal font baking API and simplified\n///                        font atlas memory management by converting pointer\n///                        arrays for fonts and font configurations to lists.\n/// - 2016/07/15 (1.00.0) - Changed button API to use context dependent button\n///                        behavior instead of passing it for every function call.\n/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n/// ## Gallery\n/// ![Figure [blue]: Feature overview with blue color styling](https://cloud.githubusercontent.com/assets/8057201/13538240/acd96876-e249-11e5-9547-5ac0b19667a0.png)\n/// ![Figure [red]: Feature overview with red color styling](https://cloud.githubusercontent.com/assets/8057201/13538243/b04acd4c-e249-11e5-8fd2-ad7744a5b446.png)\n/// ![Figure [widgets]: Widget overview](https://cloud.githubusercontent.com/assets/8057201/11282359/3325e3c6-8eff-11e5-86cb-cf02b0596087.png)\n/// ![Figure [blackwhite]: Black and white](https://cloud.githubusercontent.com/assets/8057201/11033668/59ab5d04-86e5-11e5-8091-c56f16411565.png)\n/// ![Figure [filexp]: File explorer](https://cloud.githubusercontent.com/assets/8057201/10718115/02a9ba08-7b6b-11e5-950f-adacdd637739.png)\n/// ![Figure [opengl]: OpenGL Editor](https://cloud.githubusercontent.com/assets/8057201/12779619/2a20d72c-ca69-11e5-95fe-4edecf820d5c.png)\n/// ![Figure [nodedit]: Node Editor](https://cloud.githubusercontent.com/assets/8057201/9976995/e81ac04a-5ef7-11e5-872b-acd54fbeee03.gif)\n/// ![Figure [skinning]: Using skinning in Nuklear](https://cloud.githubusercontent.com/assets/8057201/15991632/76494854-30b8-11e6-9555-a69840d0d50b.png)\n/// ![Figure [bf]: Heavy modified version](https://cloud.githubusercontent.com/assets/8057201/14902576/339926a8-0d9c-11e6-9fee-a8b73af04473.png)\n///\n/// ## Credits\n/// Developed by Micha Mettke and every direct or indirect github contributor. <br /><br />\n///\n/// Embeds [stb_texedit](https://github.com/nothings/stb/blob/master/stb_textedit.h), [stb_truetype](https://github.com/nothings/stb/blob/master/stb_truetype.h) and [stb_rectpack](https://github.com/nothings/stb/blob/master/stb_rect_pack.h) by Sean Barret (public domain) <br />\n/// Uses [stddoc.c](https://github.com/r-lyeh/stddoc.c) from r-lyeh@github.com for documentation generation <br /><br />\n/// Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license). <br />\n///\n/// Big thank you to Omar Cornut (ocornut@github) for his [imgui library](https://github.com/ocornut/imgui) and\n/// giving me the inspiration for this library, Casey Muratori for handmade hero\n/// and his original immediate mode graphical user interface idea and Sean\n/// Barret for his amazing single header libraries which restored my faith\n/// in libraries and brought me to create some of my own. Finally Apoorva Joshi\n/// for his single header file packer.\n*/\n\n"
  },
  {
    "path": "src/CHANGELOG",
    "content": "/// ## Changelog\n/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none\n/// [date] ([x.y.z]) - [description]\n/// - [date]: date on which the change has been pushed\n/// - [x.y.z]: Version string, represented in Semantic Versioning format\n///   - [x]: Major version with API and library breaking changes\n///   - [y]: Minor version with non-breaking API and library changes\n///   - [z]: Patch version with no direct changes to the API\n///\n/// - 2026/01/31 (4.13.2) - Fix: replace incorrect static asserts for size(nk_bool)\n/// - 2026/01/26 (4.13.1) - Fix: nk_do_property now uses NK_STRTOD via macro\n///                       - Fix: failure to build from source, due to\n///                         nuklear_math/util.c not declaring some functions\n///                       - Fix: guard nk_strtod implementation with preprocessor\n///                       - Fix: nuklear_sdl3_renderer now provides NK_DTOA\n///                       - Fix: guard nk_pow, nk_ifloord, nk_log10 with preprocessor\n/// - 2025/11/15 (4.13.0) - Fix: nk_property not updating 'win->edit.active'\n///                         Add new updated demo: sdl3_renderer\n/// - 2025/10/08 (4.12.8) - Fix nk_widget_text to use NK_TEXT_ALIGN_LEFT by default,\n///                         instead of silently failing when no x-axis alignment is provided,\n///                         and refactor this function to keep the code style consistent\n/// - 2025/09/12 (4.12.8) - Fix nk_window_is_hovered to use current window flags\n                          - Fix nk_utf_decode length check (allow len == NK_UTF_SIZE)\n/// - 2025/04/28 (4.12.8) - Allow switching between TEXT_INSERT and TEXT_REPLACE modes directly\n/// - 2025/04/06 (4.12.7) - Fix text input navigation and mouse scrolling\n/// - 2025/03/29 (4.12.6) - Fix unitialized data in nk_input_char\n/// - 2025/03/05 (4.12.5) - Fix scrolling knob also scrolling parent window, remove dead code\n/// - 2024/12/11 (4.12.4) - Fix array subscript [0, 0] is outside array bounds of ‘char[1]’\n/// - 2024/12/11 (4.12.3) - Fix border color for property widgets\n/// - 2024/11/20 (4.12.2) - Fix int/float type conversion warnings in `nk_roundf`\n/// - 2024/03/07 (4.12.1) - Fix bitwise operations warnings in C++20\n/// - 2023/11/26 (4.12.0) - Added an alignment option to checkboxes and radio buttons.\n/// - 2023/10/11 (4.11.0) - Added nk_widget_disable_begin() and nk_widget_disable_end()\n/// - 2022/12/23 (4.10.6) - Fix incorrect glyph index in nk_font_bake()\n/// - 2022/12/17 (4.10.5) - Fix nk_font_bake_pack() using TTC font offset incorrectly\n/// - 2022/10/24 (4.10.4) - Fix nk_str_{append,insert}_str_utf8 always returning 0\n/// - 2022/09/03 (4.10.3) - Renamed the `null` texture variable to `tex_null`\n/// - 2022/08/01 (4.10.2) - Fix Apple Silicon with incorrect NK_SITE_TYPE and NK_POINTER_TYPE\n/// - 2022/08/01 (4.10.1) - Fix cursor jumping back to beginning of text when typing more than\n///                         nk_edit_xxx limit\n/// - 2022/05/27 (4.10.0) - Add nk_input_has_mouse_click_in_button_rect() to fix window move bug\n/// - 2022/04/19 (4.9.8)  - Added nk_rule_horizontal() widget\n/// - 2022/04/18 (4.9.7)  - Change button behavior when NK_BUTTON_TRIGGER_ON_RELEASE is defined to\n///                         only trigger when the mouse position was inside the same button on down\n/// - 2022/02/03 (4.9.6)  - Allow overriding the NK_INV_SQRT function, similar to NK_SIN and NK_COS\n/// - 2021/12/22 (4.9.5)  - Revert layout bounds not accounting for padding due to regressions\n/// - 2021/12/22 (4.9.4)  - Fix checking hovering when window is minimized\n/// - 2021/12/22 (4.09.3) - Fix layout bounds not accounting for padding\n/// - 2021/12/19 (4.09.2) - Update to stb_rect_pack.h v1.01 and stb_truetype.h v1.26\n/// - 2021/12/16 (4.09.1) - Fix the majority of GCC warnings\n/// - 2021/10/16 (4.09.0) - Added nk_spacer() widget\n/// - 2021/09/22 (4.08.6) - Fix \"may be used uninitialized\" warnings in nk_widget\n/// - 2021/09/22 (4.08.5) - GCC __builtin_offsetof only exists in version 4 and later\n/// - 2021/09/15 (4.08.4) - Fix \"'num_len' may be used uninitialized\" in nk_do_property\n/// - 2021/09/15 (4.08.3) - Fix \"Templates cannot be declared to have 'C' Linkage\"\n/// - 2021/09/08 (4.08.2) - Fix warnings in C89 builds\n/// - 2021/09/08 (4.08.1) - Use compiler builtins for NK_OFFSETOF when possible\n/// - 2021/08/17 (4.08.0) - Implemented 9-slice scaling support for widget styles\n/// - 2021/08/16 (4.07.5) - Replace usage of memset in nk_font_atlas_bake with NK_MEMSET\n/// - 2021/08/15 (4.07.4) - Fix conversion and sign conversion warnings\n/// - 2021/08/08 (4.07.3) - Fix crash when baking merged fonts\n/// - 2021/08/08 (4.07.2) - Fix Multiline Edit wrong offset\n/// - 2021/03/17 (4.07.1) - Fix warning about unused parameter\n/// - 2021/03/17 (4.07.0) - Fix nk_property hover bug\n/// - 2021/03/15 (4.06.4) - Change nk_propertyi back to int\n/// - 2021/03/15 (4.06.3) - Update documentation for functions that now return nk_bool\n/// - 2020/12/19 (4.06.2) - Fix additional C++ style comments which are not allowed in ISO C90.\n/// - 2020/10/11 (4.06.1) - Fix C++ style comments which are not allowed in ISO C90.\n/// - 2020/10/07 (4.06.0) - Fix nk_combo return type wrongly changed to nk_bool\n/// - 2020/09/05 (4.05.0) - Use the nk_font_atlas allocator for stb_truetype memory management.\n/// - 2020/09/04 (4.04.1) - Replace every boolean int by nk_bool\n/// - 2020/09/04 (4.04.0) - Add nk_bool with NK_INCLUDE_STANDARD_BOOL\n/// - 2020/06/13 (4.03.1) - Fix nk_pool allocation sizes.\n/// - 2020/06/04 (4.03.0) - Made nk_combo header symbols optional.\n/// - 2020/05/27 (4.02.5) - Fix nk_do_edit: Keep scroll position when re-activating edit widget.\n/// - 2020/05/09 (4.02.4) - Fix nk_menubar height calculation bug\n/// - 2020/05/08 (4.02.3) - Fix missing stdarg.h with NK_INCLUDE_STANDARD_VARARGS\n/// - 2020/04/30 (4.02.2) - Fix nk_edit border drawing bug\n/// - 2020/04/09 (4.02.1) - Removed unused nk_sqrt function to fix compiler warnings\n///                       - Fixed compiler warnings if you bring your own methods for\n///                        nk_cos/nk_sin/nk_strtod/nk_memset/nk_memcopy/nk_dtoa\n/// - 2020/04/06 (4.01.10) - Fix bug: Do not use pool before checking for NULL\n/// - 2020/03/22 (4.01.9) - Fix bug where layout state wasn't restored correctly after\n///                        popping a tree.\n/// - 2020/03/11 (4.01.8) - Fix bug where padding is subtracted from widget\n/// - 2020/03/06 (4.01.7) - Fix bug where width padding was applied twice\n/// - 2020/02/06 (4.01.6) - Update stb_truetype.h and stb_rect_pack.h and separate them\n/// - 2019/12/10 (4.01.5) - Fix off-by-one error in NK_INTERSECT\n/// - 2019/10/09 (4.01.4) - Fix bug for autoscrolling in nk_do_edit\n/// - 2019/09/20 (4.01.3) - Fixed a bug wherein combobox cannot be closed by clicking the header\n///                        when NK_BUTTON_TRIGGER_ON_RELEASE is defined.\n/// - 2019/09/10 (4.01.2) - Fixed the nk_cos function, which deviated significantly.\n/// - 2019/09/08 (4.01.1) - Fixed a bug wherein re-baking of fonts caused a segmentation\n///                        fault due to dst_font->glyph_count not being zeroed on subsequent\n///                        bakes of the same set of fonts.\n/// - 2019/06/23 (4.01.0) - Added nk_***_get_scroll and nk_***_set_scroll for groups, windows, and popups.\n/// - 2019/06/12 (4.00.3) - Fix panel background drawing bug.\n/// - 2018/10/31 (4.00.2) - Added NK_KEYSTATE_BASED_INPUT to \"fix\" state based backends\n///                        like GLFW without breaking key repeat behavior on event based.\n/// - 2018/04/01 (4.00.1) - Fixed calling `nk_convert` multiple time per single frame.\n/// - 2018/04/01 (4.00.0) - BREAKING CHANGE: nk_draw_list_clear no longer tries to\n///                        clear provided buffers. So make sure to either free\n///                        or clear each passed buffer after calling nk_convert.\n/// - 2018/02/23 (3.00.6) - Fixed slider dragging behavior.\n/// - 2018/01/31 (3.00.5) - Fixed overcalculation of cursor data in font baking process.\n/// - 2018/01/31 (3.00.4) - Removed name collision with stb_truetype.\n/// - 2018/01/28 (3.00.3) - Fixed panel window border drawing bug.\n/// - 2018/01/12 (3.00.2) - Added `nk_group_begin_titled` for separated group identifier and title.\n/// - 2018/01/07 (3.00.1) - Started to change documentation style.\n/// - 2018/01/05 (3.00.0) - BREAKING CHANGE: The previous color picker API was broken\n///                        because of conversions between float and byte color representation.\n///                        Color pickers now use floating point values to represent\n///                        HSV values. To get back the old behavior I added some additional\n///                        color conversion functions to cast between nk_color and\n///                        nk_colorf.\n/// - 2017/12/23 (2.00.7) - Fixed small warning.\n/// - 2017/12/23 (2.00.7) - Fixed `nk_edit_buffer` behavior if activated to allow input.\n/// - 2017/12/23 (2.00.7) - Fixed modifyable progressbar dragging visuals and input behavior.\n/// - 2017/12/04 (2.00.6) - Added formatted string tooltip widget.\n/// - 2017/11/18 (2.00.5) - Fixed window becoming hidden with flag `NK_WINDOW_NO_INPUT`.\n/// - 2017/11/15 (2.00.4) - Fixed font merging.\n/// - 2017/11/07 (2.00.3) - Fixed window size and position modifier functions.\n/// - 2017/09/14 (2.00.2) - Fixed `nk_edit_buffer` and `nk_edit_focus` behavior.\n/// - 2017/09/14 (2.00.1) - Fixed window closing behavior.\n/// - 2017/09/14 (2.00.0) - BREAKING CHANGE: Modifying window position and size functions now\n///                        require the name of the window and must happen outside the window\n///                        building process (between function call nk_begin and nk_end).\n/// - 2017/09/11 (1.40.9) - Fixed window background flag if background window is declared last.\n/// - 2017/08/27 (1.40.8) - Fixed `nk_item_is_any_active` for hidden windows.\n/// - 2017/08/27 (1.40.7) - Fixed window background flag.\n/// - 2017/07/07 (1.40.6) - Fixed missing clipping rect check for hovering/clicked\n///                        query for widgets.\n/// - 2017/07/07 (1.40.5) - Fixed drawing bug for vertex output for lines and stroked\n///                        and filled rectangles.\n/// - 2017/07/07 (1.40.4) - Fixed bug in nk_convert trying to add windows that are in\n///                        process of being destroyed.\n/// - 2017/07/07 (1.40.3) - Fixed table internal bug caused by storing table size in\n///                        window instead of directly in table.\n/// - 2017/06/30 (1.40.2) - Removed unneeded semicolon in C++ NK_ALIGNOF macro.\n/// - 2017/06/30 (1.40.1) - Fixed drawing lines smaller or equal zero.\n/// - 2017/06/08 (1.40.0) - Removed the breaking part of last commit. Auto layout now only\n///                        comes in effect if you pass in zero was row height argument.\n/// - 2017/06/08 (1.40.0) - BREAKING CHANGE: while not directly API breaking it will change\n///                        how layouting works. From now there will be an internal minimum\n///                        row height derived from font height. If you need a row smaller than\n///                        that you can directly set it by `nk_layout_set_min_row_height` and\n///                        reset the value back by calling `nk_layout_reset_min_row_height.\n/// - 2017/06/08 (1.39.1) - Fixed property text edit handling bug caused by past `nk_widget` fix.\n/// - 2017/06/08 (1.39.0) - Added function to retrieve window space without calling a `nk_layout_xxx` function.\n/// - 2017/06/06 (1.38.5) - Fixed `nk_convert` return flag for command buffer.\n/// - 2017/05/23 (1.38.4) - Fixed activation behavior for widgets partially clipped.\n/// - 2017/05/10 (1.38.3) - Fixed wrong min window size mouse scaling over boundaries.\n/// - 2017/05/09 (1.38.2) - Fixed vertical scrollbar drawing with not enough space.\n/// - 2017/05/09 (1.38.1) - Fixed scaler dragging behavior if window size hits minimum size.\n/// - 2017/05/06 (1.38.0) - Added platform double-click support.\n/// - 2017/04/20 (1.37.1) - Fixed key repeat found inside glfw demo backends.\n/// - 2017/04/20 (1.37.0) - Extended properties with selection and clipboard support.\n/// - 2017/04/20 (1.36.2) - Fixed #405 overlapping rows with zero padding and spacing.\n/// - 2017/04/09 (1.36.1) - Fixed #403 with another widget float error.\n/// - 2017/04/09 (1.36.0) - Added window `NK_WINDOW_NO_INPUT` and `NK_WINDOW_NOT_INTERACTIVE` flags.\n/// - 2017/04/09 (1.35.3) - Fixed buffer heap corruption.\n/// - 2017/03/25 (1.35.2) - Fixed popup overlapping for `NK_WINDOW_BACKGROUND` windows.\n/// - 2017/03/25 (1.35.1) - Fixed windows closing behavior.\n/// - 2017/03/18 (1.35.0) - Added horizontal scroll requested in #377.\n/// - 2017/03/18 (1.34.3) - Fixed long window header titles.\n/// - 2017/03/04 (1.34.2) - Fixed text edit filtering.\n/// - 2017/03/04 (1.34.1) - Fixed group closable flag.\n/// - 2017/02/25 (1.34.0) - Added custom draw command for better language binding support.\n/// - 2017/01/24 (1.33.0) - Added programmatic way to remove edit focus.\n/// - 2017/01/24 (1.32.3) - Fixed wrong define for basic type definitions for windows.\n/// - 2017/01/21 (1.32.2) - Fixed input capture from hidden or closed windows.\n/// - 2017/01/21 (1.32.1) - Fixed slider behavior and drawing.\n/// - 2017/01/13 (1.32.0) - Added flag to put scaler into the bottom left corner.\n/// - 2017/01/13 (1.31.0) - Added additional row layouting method to combine both\n///                        dynamic and static widgets.\n/// - 2016/12/31 (1.30.0) - Extended scrollbar offset from 16-bit to 32-bit.\n/// - 2016/12/31 (1.29.2) - Fixed closing window bug of minimized windows.\n/// - 2016/12/03 (1.29.1) - Fixed wrapped text with no separator and C89 error.\n/// - 2016/12/03 (1.29.0) - Changed text wrapping to process words not characters.\n/// - 2016/11/22 (1.28.6) - Fixed window minimized closing bug.\n/// - 2016/11/19 (1.28.5) - Fixed abstract combo box closing behavior.\n/// - 2016/11/19 (1.28.4) - Fixed tooltip flickering.\n/// - 2016/11/19 (1.28.3) - Fixed memory leak caused by popup repeated closing.\n/// - 2016/11/18 (1.28.2) - Fixed memory leak caused by popup panel allocation.\n/// - 2016/11/10 (1.28.1) - Fixed some warnings and C++ error.\n/// - 2016/11/10 (1.28.0) - Added additional `nk_button` versions which allows to directly\n///                        pass in a style struct to change buttons visual.\n/// - 2016/11/10 (1.27.0) - Added additional `nk_tree` versions to support external state\n///                        storage. Just like last the `nk_group` commit the main\n///                        advantage is that you optionally can minimize nuklears runtime\n///                        memory consumption or handle hash collisions.\n/// - 2016/11/09 (1.26.0) - Added additional `nk_group` version to support external scrollbar\n///                        offset storage. Main advantage is that you can externalize\n///                        the memory management for the offset. It could also be helpful\n///                        if you have a hash collision in `nk_group_begin` but really\n///                        want the name. In addition I added `nk_list_view` which allows\n///                        to draw big lists inside a group without actually having to\n///                        commit the whole list to nuklear (issue #269).\n/// - 2016/10/30 (1.25.1) - Fixed clipping rectangle bug inside `nk_draw_list`.\n/// - 2016/10/29 (1.25.0) - Pulled `nk_panel` memory management into nuklear and out of\n///                        the hands of the user. From now on users don't have to care\n///                        about panels unless they care about some information. If you\n///                        still need the panel just call `nk_window_get_panel`.\n/// - 2016/10/21 (1.24.0) - Changed widget border drawing to stroked rectangle from filled\n///                        rectangle for less overdraw and widget background transparency.\n/// - 2016/10/18 (1.23.0) - Added `nk_edit_focus` for manually edit widget focus control.\n/// - 2016/09/29 (1.22.7) - Fixed deduction of basic type in non `<stdint.h>` compilation.\n/// - 2016/09/29 (1.22.6) - Fixed edit widget UTF-8 text cursor drawing bug.\n/// - 2016/09/28 (1.22.5) - Fixed edit widget UTF-8 text appending/inserting/removing.\n/// - 2016/09/28 (1.22.4) - Fixed drawing bug inside edit widgets which offset all text\n///                        text in every edit widget if one of them is scrolled.\n/// - 2016/09/28 (1.22.3) - Fixed small bug in edit widgets if not active. The wrong\n///                        text length is passed. It should have been in bytes but\n///                        was passed as glyphs.\n/// - 2016/09/20 (1.22.2) - Fixed color button size calculation.\n/// - 2016/09/20 (1.22.1) - Fixed some `nk_vsnprintf` behavior bugs and removed `<stdio.h>`\n///                        again from `NK_INCLUDE_STANDARD_VARARGS`.\n/// - 2016/09/18 (1.22.0) - C89 does not support vsnprintf only C99 and newer as well\n///                        as C++11 and newer. In addition to use vsnprintf you have\n///                        to include <stdio.h>. So just defining `NK_INCLUDE_STD_VAR_ARGS`\n///                        is not enough. That behavior is now fixed. By default if\n///                        both varargs as well as stdio is selected I try to use\n///                        vsnprintf if not possible I will revert to vsprintf. If\n///                        varargs but not stdio was defined I will use my own function.\n/// - 2016/09/15 (1.21.2) - Fixed panel `close` behavior for deeper panel levels.\n/// - 2016/09/15 (1.21.1) - Fixed C++ errors and wrong argument to `nk_panel_get_xxxx`.\n/// - 2016/09/13 (1.21.0) - !BREAKING! Fixed nonblocking popup behavior in menu, combo,\n///                        and contextual which prevented closing in y-direction if\n///                        popup did not reach max height.\n///                        In addition the height parameter was changed into vec2\n///                        for width and height to have more control over the popup size.\n/// - 2016/09/13 (1.20.3) - Cleaned up and extended type selection.\n/// - 2016/09/13 (1.20.2) - Fixed slider behavior hopefully for the last time. This time\n///                        all calculation are correct so no more hackery.\n/// - 2016/09/13 (1.20.1) - Internal change to divide window/panel flags into panel flags and types.\n///                        Suprisinly spend years in C and still happened to confuse types\n///                        with flags. Probably something to take note.\n/// - 2016/09/08 (1.20.0) - Added additional helper function to make it easier to just\n///                        take the produced buffers from `nk_convert` and unplug the\n///                        iteration process from `nk_context`. So now you can\n///                        just use the vertex,element and command buffer + two pointer\n///                        inside the command buffer retrieved by calls `nk__draw_begin`\n///                        and `nk__draw_end` and macro `nk_draw_foreach_bounded`.\n/// - 2016/09/08 (1.19.0) - Added additional asserts to make sure every `nk_xxx_begin` call\n///                        for windows, popups, combobox, menu and contextual is guarded by\n///                        `if` condition and does not produce false drawing output.\n/// - 2016/09/08 (1.18.0) - Changed confusing name for `NK_SYMBOL_RECT_FILLED`, `NK_SYMBOL_RECT`\n///                        to hopefully easier to understand `NK_SYMBOL_RECT_FILLED` and\n///                        `NK_SYMBOL_RECT_OUTLINE`.\n/// - 2016/09/08 (1.17.0) - Changed confusing name for `NK_SYMBOL_CIRLCE_FILLED`, `NK_SYMBOL_CIRCLE`\n///                        to hopefully easier to understand `NK_SYMBOL_CIRCLE_FILLED` and\n///                        `NK_SYMBOL_CIRCLE_OUTLINE`.\n/// - 2016/09/08 (1.16.0) - Added additional checks to select correct types if `NK_INCLUDE_FIXED_TYPES`\n///                        is not defined by supporting the biggest compiler GCC, clang and MSVC.\n/// - 2016/09/07 (1.15.3) - Fixed `NK_INCLUDE_COMMAND_USERDATA` define to not cause an error.\n/// - 2016/09/04 (1.15.2) - Fixed wrong combobox height calculation.\n/// - 2016/09/03 (1.15.1) - Fixed gaps inside combo boxes in OpenGL.\n/// - 2016/09/02 (1.15.0) - Changed nuklear to not have any default vertex layout and\n///                        instead made it user provided. The range of types to convert\n///                        to is quite limited at the moment, but I would be more than\n///                        happy to accept PRs to add additional.\n/// - 2016/08/30 (1.14.2) - Removed unused variables.\n/// - 2016/08/30 (1.14.1) - Fixed C++ build errors.\n/// - 2016/08/30 (1.14.0) - Removed mouse dragging from SDL demo since it does not work correctly.\n/// - 2016/08/30 (1.13.4) - Tweaked some default styling variables.\n/// - 2016/08/30 (1.13.3) - Hopefully fixed drawing bug in slider, in general I would\n///                        refrain from using slider with a big number of steps.\n/// - 2016/08/30 (1.13.2) - Fixed close and minimize button which would fire even if the\n///                        window was in Read Only Mode.\n/// - 2016/08/30 (1.13.1) - Fixed popup panel padding handling which was previously just\n///                        a hack for combo box and menu.\n/// - 2016/08/30 (1.13.0) - Removed `NK_WINDOW_DYNAMIC` flag from public API since\n///                        it is bugged and causes issues in window selection.\n/// - 2016/08/30 (1.12.0) - Removed scaler size. The size of the scaler is now\n///                        determined by the scrollbar size.\n/// - 2016/08/30 (1.11.2) - Fixed some drawing bugs caused by changes from 1.11.0.\n/// - 2016/08/30 (1.11.1) - Fixed overlapping minimized window selection.\n/// - 2016/08/30 (1.11.0) - Removed some internal complexity and overly complex code\n///                        handling panel padding and panel border.\n/// - 2016/08/29 (1.10.0) - Added additional height parameter to `nk_combobox_xxx`.\n/// - 2016/08/29 (1.10.0) - Fixed drawing bug in dynamic popups.\n/// - 2016/08/29 (1.10.0) - Added experimental mouse scrolling to popups, menus and comboboxes.\n/// - 2016/08/26 (1.10.0) - Added window name string prepresentation to account for\n///                        hash collisions. Currently limited to `NK_WINDOW_MAX_NAME`\n///                        which in term can be redefined if not big enough.\n/// - 2016/08/26 (1.10.0) - Added stacks for temporary style/UI changes in code.\n/// - 2016/08/25 (1.10.0) - Changed `nk_input_is_key_pressed` and 'nk_input_is_key_released'\n///                        to account for key press and release happening in one frame.\n/// - 2016/08/25 (1.10.0) - Added additional nk_edit flag to directly jump to the end on activate.\n/// - 2016/08/17 (1.09.6) - Removed invalid check for value zero in `nk_propertyx`.\n/// - 2016/08/16 (1.09.5) - Fixed ROM mode for deeper levels of popup windows parents.\n/// - 2016/08/15 (1.09.4) - Editbox are now still active if enter was pressed with flag\n///                        `NK_EDIT_SIG_ENTER`. Main reasoning is to be able to keep\n///                        typing after committing.\n/// - 2016/08/15 (1.09.4) - Removed redundant code.\n/// - 2016/08/15 (1.09.4) - Fixed negative numbers in `nk_strtoi` and remove unused variable.\n/// - 2016/08/15 (1.09.3) - Fixed `NK_WINDOW_BACKGROUND` flag behavior to select a background\n///                        window only as selected by hovering and not by clicking.\n/// - 2016/08/14 (1.09.2) - Fixed a bug in font atlas which caused wrong loading\n///                        of glyphs for font with multiple ranges.\n/// - 2016/08/12 (1.09.1) - Added additional function to check if window is currently\n///                        hidden and therefore not visible.\n/// - 2016/08/12 (1.09.1) - nk_window_is_closed now queries the correct flag `NK_WINDOW_CLOSED`\n///                        instead of the old flag `NK_WINDOW_HIDDEN`.\n/// - 2016/08/09 (1.09.0) - Added additional double version to nk_property and changed\n///                        the underlying implementation to not cast to float and instead\n///                        work directly on the given values.\n/// - 2016/08/09 (1.08.0) - Added additional define to overwrite library internal\n///                        floating pointer number to string conversion for additional\n///                        precision.\n/// - 2016/08/09 (1.08.0) - Added additional define to overwrite library internal\n///                        string to floating point number conversion for additional\n///                        precision.\n/// - 2016/08/08 (1.07.2) - Fixed compiling error without define `NK_INCLUDE_FIXED_TYPE`.\n/// - 2016/08/08 (1.07.1) - Fixed possible floating point error inside `nk_widget` leading\n///                        to wrong widget width calculation which results in widgets falsely\n///                        becoming tagged as not inside window and cannot be accessed.\n/// - 2016/08/08 (1.07.0) - Nuklear now differentiates between hiding a window (NK_WINDOW_HIDDEN) and\n///                        closing a window (NK_WINDOW_CLOSED). A window can be hidden/shown\n///                        by using `nk_window_show` and closed by either clicking the close\n///                        icon in a window or by calling `nk_window_close`. Only closed\n///                        windows get removed at the end of the frame while hidden windows\n///                        remain.\n/// - 2016/08/08 (1.06.0) - Added `nk_edit_string_zero_terminated` as a second option to\n///                        `nk_edit_string` which takes, edits and outputs a '\\0' terminated string.\n/// - 2016/08/08 (1.05.4) - Fixed scrollbar auto hiding behavior.\n/// - 2016/08/08 (1.05.3) - Fixed wrong panel padding selection in `nk_layout_widget_space`.\n/// - 2016/08/07 (1.05.2) - Fixed old bug in dynamic immediate mode layout API, calculating\n///                        wrong item spacing and panel width.\n/// - 2016/08/07 (1.05.1) - Hopefully finally fixed combobox popup drawing bug.\n/// - 2016/08/07 (1.05.0) - Split varargs away from `NK_INCLUDE_STANDARD_IO` into own\n///                        define `NK_INCLUDE_STANDARD_VARARGS` to allow more fine\n///                        grained controlled over library includes.\n/// - 2016/08/06 (1.04.5) - Changed memset calls to `NK_MEMSET`.\n/// - 2016/08/04 (1.04.4) - Fixed fast window scaling behavior.\n/// - 2016/08/04 (1.04.3) - Fixed window scaling, movement bug which appears if you\n///                        move/scale a window and another window is behind it.\n///                        If you are fast enough then the window behind gets activated\n///                        and the operation is blocked. I now require activating\n///                        by hovering only if mouse is not pressed.\n/// - 2016/08/04 (1.04.2) - Fixed changing fonts.\n/// - 2016/08/03 (1.04.1) - Fixed `NK_WINDOW_BACKGROUND` behavior.\n/// - 2016/08/03 (1.04.0) - Added color parameter to `nk_draw_image`.\n/// - 2016/08/03 (1.04.0) - Added additional window padding style attributes for\n///                        sub windows (combo, menu, ...).\n/// - 2016/08/03 (1.04.0) - Added functions to show/hide software cursor.\n/// - 2016/08/03 (1.04.0) - Added `NK_WINDOW_BACKGROUND` flag to force a window\n///                        to be always in the background of the screen.\n/// - 2016/08/03 (1.03.2) - Removed invalid assert macro for NK_RGB color picker.\n/// - 2016/08/01 (1.03.1) - Added helper macros into header include guard.\n/// - 2016/07/29 (1.03.0) - Moved the window/table pool into the header part to\n///                        simplify memory management by removing the need to\n///                        allocate the pool.\n/// - 2016/07/29 (1.02.0) - Added auto scrollbar hiding window flag which if enabled\n///                        will hide the window scrollbar after NK_SCROLLBAR_HIDING_TIMEOUT\n///                        seconds without window interaction. To make it work\n///                        you have to also set a delta time inside the `nk_context`.\n/// - 2016/07/25 (1.01.1) - Fixed small panel and panel border drawing bugs.\n/// - 2016/07/15 (1.01.0) - Added software cursor to `nk_style` and `nk_context`.\n/// - 2016/07/15 (1.01.0) - Added const correctness to `nk_buffer_push' data argument.\n/// - 2016/07/15 (1.01.0) - Removed internal font baking API and simplified\n///                        font atlas memory management by converting pointer\n///                        arrays for fonts and font configurations to lists.\n/// - 2016/07/15 (1.00.0) - Changed button API to use context dependent button\n///                        behavior instead of passing it for every function call.\n/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
  },
  {
    "path": "src/CREDITS",
    "content": "/// ## Gallery\n/// ![Figure [blue]: Feature overview with blue color styling](https://cloud.githubusercontent.com/assets/8057201/13538240/acd96876-e249-11e5-9547-5ac0b19667a0.png)\n/// ![Figure [red]: Feature overview with red color styling](https://cloud.githubusercontent.com/assets/8057201/13538243/b04acd4c-e249-11e5-8fd2-ad7744a5b446.png)\n/// ![Figure [widgets]: Widget overview](https://cloud.githubusercontent.com/assets/8057201/11282359/3325e3c6-8eff-11e5-86cb-cf02b0596087.png)\n/// ![Figure [blackwhite]: Black and white](https://cloud.githubusercontent.com/assets/8057201/11033668/59ab5d04-86e5-11e5-8091-c56f16411565.png)\n/// ![Figure [filexp]: File explorer](https://cloud.githubusercontent.com/assets/8057201/10718115/02a9ba08-7b6b-11e5-950f-adacdd637739.png)\n/// ![Figure [opengl]: OpenGL Editor](https://cloud.githubusercontent.com/assets/8057201/12779619/2a20d72c-ca69-11e5-95fe-4edecf820d5c.png)\n/// ![Figure [nodedit]: Node Editor](https://cloud.githubusercontent.com/assets/8057201/9976995/e81ac04a-5ef7-11e5-872b-acd54fbeee03.gif)\n/// ![Figure [skinning]: Using skinning in Nuklear](https://cloud.githubusercontent.com/assets/8057201/15991632/76494854-30b8-11e6-9555-a69840d0d50b.png)\n/// ![Figure [bf]: Heavy modified version](https://cloud.githubusercontent.com/assets/8057201/14902576/339926a8-0d9c-11e6-9fee-a8b73af04473.png)\n///\n/// ## Credits\n/// Developed by Micha Mettke and every direct or indirect github contributor. <br /><br />\n///\n/// Embeds [stb_texedit](https://github.com/nothings/stb/blob/master/stb_textedit.h), [stb_truetype](https://github.com/nothings/stb/blob/master/stb_truetype.h) and [stb_rectpack](https://github.com/nothings/stb/blob/master/stb_rect_pack.h) by Sean Barret (public domain) <br />\n/// Uses [stddoc.c](https://github.com/r-lyeh/stddoc.c) from r-lyeh@github.com for documentation generation <br /><br />\n/// Embeds ProggyClean.ttf font by Tristan Grimmer (MIT license). <br />\n///\n/// Big thank you to Omar Cornut (ocornut@github) for his [imgui library](https://github.com/ocornut/imgui) and\n/// giving me the inspiration for this library, Casey Muratori for handmade hero\n/// and his original immediate mode graphical user interface idea and Sean\n/// Barret for his amazing single header libraries which restored my faith\n/// in libraries and brought me to create some of my own. Finally Apoorva Joshi\n/// for his single header file packer.\n"
  },
  {
    "path": "src/HEADER.md",
    "content": "# Nuklear\n![](https://cloud.githubusercontent.com/assets/8057201/11761525/ae06f0ca-a0c6-11e5-819d-5610b25f6ef4.gif)\n\n## Contents\n1. About section\n2. Highlights section\n3. Features section\n4. Usage section\n    1. Flags section\n    2. Constants section\n    3. Dependencies section\n5. Example section\n6. API section\n    1. Context section\n    2. Input section\n    3. Drawing section\n    4. Window section\n    5. Layouting section\n    6. Groups section\n    7. Tree section\n    8. Properties section\n7. License section\n8. Changelog section\n9. Gallery section\n10. Credits section\n\n## About\nThis is a minimal state immediate mode graphical user interface toolkit\nwritten in ANSI C and licensed under public domain. It was designed as a simple\nembeddable user interface for application and does not have any dependencies,\na default renderbackend or OS window and input handling but instead provides a very modular\nlibrary approach by using simple input state for input and draw\ncommands describing primitive shapes as output. So instead of providing a\nlayered library that tries to abstract over a number of platform and\nrender backends it only focuses on the actual UI.\n\n## Highlights\n- Graphical user interface toolkit\n- Single header library\n- Written in C89 (a.k.a. ANSI C or ISO C90)\n- Small codebase (~18kLOC)\n- Focus on portability, efficiency and simplicity\n- No dependencies (not even the standard library if not wanted)\n- Fully skinnable and customizable\n- Low memory footprint with total memory control if needed or wanted\n- UTF-8 support\n- No global or hidden state\n- Customizable library modules (you can compile and use only what you need)\n- Optional font baker and vertex buffer output\n- [Code available on github](https://github.com/Immediate-Mode-UI/Nuklear/)\n\n## Features\n- Absolutely no platform dependent code\n- Memory management control ranging from/to\n    - Ease of use by allocating everything from standard library\n    - Control every byte of memory inside the library\n- Font handling control ranging from/to\n    - Use your own font implementation for everything\n    - Use this libraries internal font baking and handling API\n- Drawing output control ranging from/to\n    - Simple shapes for more high level APIs which already have drawing capabilities\n    - Hardware accessible anti-aliased vertex buffer output\n- Customizable colors and properties ranging from/to\n    - Simple changes to color by filling a simple color table\n    - Complete control with ability to use skinning to decorate widgets\n- Bendable UI library with widget ranging from/to\n    - Basic widgets like buttons, checkboxes, slider, ...\n    - Advanced widget like abstract comboboxes, contextual menus,...\n- Compile time configuration to only compile what you need\n    - Subset which can be used if you do not want to link or use the standard library\n- Can be easily modified to only update on user input instead of frame updates\n\n## Usage\nThis library is self contained in one single header file and can be used either\nin header only mode or in implementation mode. The header only mode is used\nby default when included and allows including this header in other headers\nand does not contain the actual implementation. <br /><br />\n\nThe implementation mode requires to define  the preprocessor macro\nNK_IMPLEMENTATION in *one* .c/.cpp file before #including this file, e.g.:\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~C\n    #define NK_IMPLEMENTATION\n    #include \"nuklear.h\"\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAlso optionally define the symbols listed in the section \"OPTIONAL DEFINES\"\nbelow in header and implementation mode if you want to use additional functionality\nor need more control over the library.\n\n!!! WARNING\n    Every time nuklear is included define the same compiler flags. This very important not doing so could lead to compiler errors or even worse stack corruptions.\n\n### Flags\nFlag                            | Description\n--------------------------------|------------------------------------------\nNK_PRIVATE                      | If defined declares all functions as static, so they can only be accessed inside the file that contains the implementation\nNK_INCLUDE_FIXED_TYPES          | If defined it will include header `<stdint.h>` for fixed sized types otherwise nuklear tries to select the correct type. If that fails it will throw a compiler error and you have to select the correct types yourself.\nNK_INCLUDE_DEFAULT_ALLOCATOR    | If defined it will include header `<stdlib.h>` and provide additional functions to use this library without caring for memory allocation control and therefore ease memory management.\nNK_INCLUDE_STANDARD_IO          | If defined it will include header `<stdio.h>` and provide additional functions depending on file loading.\nNK_INCLUDE_STANDARD_VARARGS     | If defined it will include header <stdarg.h> and provide additional functions depending on file loading.\nNK_INCLUDE_STANDARD_BOOL        | If defined it will include header `<stdbool.h>` for nk_bool otherwise nuklear defines nk_bool as int.\nNK_INCLUDE_VERTEX_BUFFER_OUTPUT | Defining this adds a vertex draw command list backend to this library, which allows you to convert queue commands into vertex draw commands. This is mainly if you need a hardware accessible format for OpenGL, DirectX, Vulkan, Metal,...\nNK_INCLUDE_FONT_BAKING          | Defining this adds `stb_truetype` and `stb_rect_pack` implementation to this library and provides font baking and rendering. If you already have font handling or do not want to use this font handler you don't have to define it.\nNK_INCLUDE_DEFAULT_FONT         | Defining this adds the default font: ProggyClean.ttf into this library which can be loaded into a font atlas and allows using this library without having a truetype font\nNK_INCLUDE_COMMAND_USERDATA     | Defining this adds a userdata pointer into each command. Can be useful for example if you want to provide custom shaders depending on the used widget. Can be combined with the style structures.\nNK_BUTTON_TRIGGER_ON_RELEASE    | Different platforms require button clicks occurring either on buttons being pressed (up to down) or released (down to up). By default this library will react on buttons being pressed, but if you define this it will only trigger if a button is released.\nNK_ZERO_COMMAND_MEMORY          | Defining this will zero out memory for each drawing command added to a drawing queue (inside nk_command_buffer_push). Zeroing command memory is very useful for fast checking (using memcmp) if command buffers are equal and avoid drawing frames when nothing on screen has changed since previous frame.\nNK_UINT_DRAW_INDEX              | Defining this will set the size of vertex index elements when using NK_VERTEX_BUFFER_OUTPUT to 32bit instead of the default of 16bit\nNK_KEYSTATE_BASED_INPUT         | Define this if your backend uses key state for each frame rather than key press/release events\nNK_IS_WORD_BOUNDARY(c)          | Define this to a function macro that takes a single nk_rune (nk_uint) and returns true if it's a word separator. If not defined, uses the default definition (see nk_is_word_boundary())\n\n!!! WARNING\n    The following flags will pull in the standard C library:\n    - NK_INCLUDE_DEFAULT_ALLOCATOR\n    - NK_INCLUDE_STANDARD_IO\n    - NK_INCLUDE_STANDARD_VARARGS\n\n!!! WARNING\n    The following flags if defined need to be defined for both header and implementation:\n    - NK_INCLUDE_FIXED_TYPES\n    - NK_INCLUDE_DEFAULT_ALLOCATOR\n    - NK_INCLUDE_STANDARD_VARARGS\n    - NK_INCLUDE_STANDARD_BOOL\n    - NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n    - NK_INCLUDE_FONT_BAKING\n    - NK_INCLUDE_DEFAULT_FONT\n    - NK_INCLUDE_STANDARD_VARARGS\n    - NK_INCLUDE_COMMAND_USERDATA\n    - NK_UINT_DRAW_INDEX\n\n### Constants\nDefine                          | Description\n--------------------------------|---------------------------------------\nNK_BUFFER_DEFAULT_INITIAL_SIZE  | Initial buffer size allocated by all buffers while using the default allocator functions included by defining NK_INCLUDE_DEFAULT_ALLOCATOR. If you don't want to allocate the default 4k memory then redefine it.\nNK_MAX_NUMBER_BUFFER            | Maximum buffer size for the conversion buffer between float and string Under normal circumstances this should be more than sufficient.\nNK_INPUT_MAX                    | Defines the max number of bytes which can be added as text input in one frame. Under normal circumstances this should be more than sufficient.\n\n!!! WARNING\n    The following constants if defined need to be defined for both header and implementation:\n    - NK_MAX_NUMBER_BUFFER\n    - NK_BUFFER_DEFAULT_INITIAL_SIZE\n    - NK_INPUT_MAX\n\n### Dependencies\nFunction    | Description\n------------|---------------------------------------------------------------\nNK_ASSERT   | If you don't define this, nuklear will use <assert.h> with assert().\nNK_MEMSET   | You can define this to 'memset' or your own memset implementation replacement. If not nuklear will use its own version.\nNK_MEMCPY   | You can define this to 'memcpy' or your own memcpy implementation replacement. If not nuklear will use its own version.\nNK_INV_SQRT | You can define this to your own inverse sqrt implementation replacement. If not nuklear will use its own slow and not highly accurate version.\nNK_SIN      | You can define this to 'sinf' or your own sine implementation replacement. If not nuklear will use its own approximation implementation.\nNK_COS      | You can define this to 'cosf' or your own cosine implementation replacement. If not nuklear will use its own approximation implementation.\nNK_STRTOD   | You can define this to `strtod` or your own string to double conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).\nNK_DTOA     | You can define this to `dtoa` or your own double to string conversion implementation replacement. If not defined nuklear will use its own imprecise and possibly unsafe version (does not handle nan or infinity!).\nNK_VSNPRINTF| If you define `NK_INCLUDE_STANDARD_VARARGS` as well as `NK_INCLUDE_STANDARD_IO` and want to be safe define this to `vsnprintf` on compilers supporting later versions of C or C++. By default nuklear will check for your stdlib version in C as well as compiler version in C++. if `vsnprintf` is available it will define it to `vsnprintf` directly. If not defined and if you have older versions of C or C++ it will be defined to `vsprintf` which is unsafe.\n\n!!! WARNING\n    The following dependencies will pull in the standard C library if not redefined:\n    - NK_ASSERT\n\n!!! WARNING\n    The following dependencies if defined need to be defined for both header and implementation:\n    - NK_ASSERT\n\n!!! WARNING\n    The following dependencies if defined need to be defined only for the implementation part:\n    - NK_MEMSET\n    - NK_MEMCPY\n    - NK_SQRT\n    - NK_SIN\n    - NK_COS\n    - NK_STRTOD\n    - NK_DTOA\n    - NK_VSNPRINTF\n\n## Example\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~c\n// init gui state\nenum {EASY, HARD};\nstatic int op = EASY;\nstatic float value = 0.6f;\nstatic int i =  20;\nstruct nk_context ctx;\n\nnk_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font);\nif (nk_begin(&ctx, \"Show\", nk_rect(50, 50, 220, 220),\n    NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) {\n    // fixed widget pixel width\n    nk_layout_row_static(&ctx, 30, 80, 1);\n    if (nk_button_label(&ctx, \"button\")) {\n        // event handling\n    }\n\n    // fixed widget window ratio width\n    nk_layout_row_dynamic(&ctx, 30, 2);\n    if (nk_option_label(&ctx, \"easy\", op == EASY)) op = EASY;\n    if (nk_option_label(&ctx, \"hard\", op == HARD)) op = HARD;\n\n    // custom widget pixel width\n    nk_layout_row_begin(&ctx, NK_STATIC, 30, 2);\n    {\n        nk_layout_row_push(&ctx, 50);\n        nk_label(&ctx, \"Volume:\", NK_TEXT_LEFT);\n        nk_layout_row_push(&ctx, 110);\n        nk_slider_float(&ctx, 0, &value, 1.0f, 0.1f);\n    }\n    nk_layout_row_end(&ctx);\n}\nnk_end(&ctx);\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n![](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png)\n\n## API\n\n"
  },
  {
    "path": "src/LICENSE",
    "content": "/// ## License\n/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~none\n///    ------------------------------------------------------------------------------\n///    This software is available under 2 licenses -- choose whichever you prefer.\n///    ------------------------------------------------------------------------------\n///    ALTERNATIVE A - MIT License\n///    Copyright (c) 2016-2018 Micha Mettke\n///    Permission is hereby granted, free of charge, to any person obtaining a copy of\n///    this software and associated documentation files (the \"Software\"), to deal in\n///    the Software without restriction, including without limitation the rights to\n///    use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\n///    of the Software, and to permit persons to whom the Software is furnished to do\n///    so, subject to the following conditions:\n///    The above copyright notice and this permission notice shall be included in all\n///    copies or substantial portions of the Software.\n///    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n///    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n///    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n///    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n///    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n///    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n///    SOFTWARE.\n///    ------------------------------------------------------------------------------\n///    ALTERNATIVE B - Public Domain (www.unlicense.org)\n///    This is free and unencumbered software released into the public domain.\n///    Anyone is free to copy, modify, publish, use, compile, sell, or distribute this\n///    software, either in source code form or as a compiled binary, for any purpose,\n///    commercial or non-commercial, and by any means.\n///    In jurisdictions that recognize copyright laws, the author or authors of this\n///    software dedicate any and all copyright interest in the software to the public\n///    domain. We make this dedication for the benefit of the public at large and to\n///    the detriment of our heirs and successors. We intend this dedication to be an\n///    overt act of relinquishment in perpetuity of all present and future rights to\n///    this software under copyright law.\n///    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n///    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n///    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n///    AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n///    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\n///    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n///    ------------------------------------------------------------------------------\n/// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n"
  },
  {
    "path": "src/Readme.md",
    "content": "File Packer:\n------------\n- On Linux/Mac just run ./paq.sh > ../nuklear.h\n- On Windows just run paq.bat\n"
  },
  {
    "path": "src/build.py",
    "content": "\nimport fnmatch\nimport os.path\nimport sys\nimport re\n\ndef print_help():\n    print(\n\"\"\"usage: python single_header_packer.py --macro <macro> [--intro <files>] --extern <files> --pub <files> --priv1 <files> --priv2 <files> [--outro <files>]\n\n       where <files> can be a comma-separated list of files. e.g. --priv *.c,inc/*.h\n       or a space separated list encapsulated in quotes. e.g. --priv1 \"file.c file2.c file3.c\"\n\n       The 'extern' files are placed between 'priv1' and 'priv2'.\n\n       The resulting code is packed as follows:\n\n           /*\n           [intro file contents]\n           */\n\n           #ifndef <macro>_SINGLE_HEADER\n           #define <macro>_SINGLE_HEADER\n           [public header file contents]\n           #endif /* <macro>_SINGLE_HEADER */\n\n           #ifdef <macro>_IMPLEMENTATION\n           [private header and source file contents]\n           #endif /* <macro>_IMPLEMENTATION */\n\n           /*\n           [outro file contents]\n           */\"\"\")\n\ndef parse_files(arg):\n    files = []\n    paths = re.split(r'[,\\s]', arg)\n\n    for path in paths:\n        if \"*\" in path:\n            # Wildcard\n            d = os.path.dirname(path)\n            if d == \"\": d = \".\"\n            if d == \" \": continue\n            if not os.path.exists(d):\n                print(d + \" does not exist.\")\n                exit()\n\n            wildcard = os.path.basename(path)\n            unsorted = []\n            for file in os.listdir(d):\n                if fnmatch.fnmatch(file, wildcard):\n                    unsorted.append(os.path.join(d, file))\n            unsorted.sort()\n            files.extend(unsorted)\n\n        else:\n            # Regular file\n            if not os.path.exists(path):\n                print(path + \" does not exist.\")\n                exit()\n            elif os.path.isdir(path):\n                print(path + \" is a directory. Expected a file name.\")\n                exit()\n            else:\n                files.append(path)\n\n    return files;\n\ndef omit_includes(str, files):\n    for file in files:\n        fname = os.path.basename(file)\n        if \".h\" in file:\n            str = str.replace(\"#include \\\"\" + fname + \"\\\"\", \"\");\n            str = str.replace(\"#include <\" + fname + \">\", \"\");\n    return str\n\ndef fix_comments(str):\n    return re.sub(r\"//(.*)(\\n|$)\", \"/* \\\\1 */\\\\2\", str)\n\n# Main start\n# ==========\n\nif len(sys.argv) < 2:\n    print_help()\n    exit()\n\nintro_files = []\npub_files = []\npriv_files1 = []\noutro_files2 = []\nextern_files = []\ncur_arg = 1\nmacro = \"\"\n\n# Parse args\n# ----------\nwhile cur_arg < len(sys.argv):\n    if sys.argv[cur_arg] == \"--help\":\n        print_help()\n        exit()\n    elif sys.argv[cur_arg] == \"--macro\":\n        cur_arg += 1\n        macro = sys.argv[cur_arg]\n    elif sys.argv[cur_arg] == \"--intro\":\n        cur_arg += 1\n        intro_files = parse_files(sys.argv[cur_arg])\n    elif sys.argv[cur_arg] == \"--pub\":\n        cur_arg += 1\n        pub_files = parse_files(sys.argv[cur_arg])\n    elif sys.argv[cur_arg] == \"--priv1\":\n        cur_arg += 1\n        priv_files1 = parse_files(sys.argv[cur_arg])\n    elif sys.argv[cur_arg] == \"--priv2\":\n        cur_arg += 1\n        priv_files2 = parse_files(sys.argv[cur_arg])\n    elif sys.argv[cur_arg] == \"--extern\":\n        cur_arg += 1\n        extern_files = parse_files(sys.argv[cur_arg])\n    elif sys.argv[cur_arg] == \"--outro\":\n        cur_arg += 1\n        outro_files = parse_files(sys.argv[cur_arg])\n    else:\n        print(\"Unknown argument \" + sys.argv[cur_arg])\n\n    cur_arg += 1\n\nif macro == \"\":\n    print(\"Option --macro <macro> is mandatory\")\n    exit()\n\n# Print concatenated output\n# -------------------------\nprint(\"/*\")\nfor f in intro_files:\n    sys.stdout.write(open(f, 'r').read())\nprint(\"*/\")\n\n# print(\"\\n#ifndef \" + macro + \"_SINGLE_HEADER\");\n# print(\"#define \" + macro + \"_SINGLE_HEADER\");\nprint(\"#ifndef NK_SINGLE_FILE\");\nprint(\"  #define NK_SINGLE_FILE\");\nprint(\"#endif\");\nprint(\"\");\n\nfor f in pub_files:\n    sys.stdout.write(open(f, 'r').read())\n# print(\"#endif /* \" + macro + \"_SINGLE_HEADER */\");\n\nprint(\"\\n#ifdef \" + macro + \"_IMPLEMENTATION\");\nprint(\"\");\n\nfor f in priv_files1:\n    print(omit_includes(open(f, 'r').read(),\n                        pub_files + priv_files1 + priv_files2 + extern_files))\nfor f in extern_files:\n    print(fix_comments(open(f, 'r').read()))\n\nfor f in priv_files2:\n    print(omit_includes(open(f, 'r').read(),\n                        pub_files + priv_files1 + priv_files2 + extern_files))\n\nprint(\"#endif /* \" + macro + \"_IMPLEMENTATION */\");\n\nprint(\"\\n/*\")\nfor f in outro_files:\n    sys.stdout.write(open(f, 'r').read())\nprint(\"*/\\n\")\n\n"
  },
  {
    "path": "src/nuklear.h",
    "content": "/** \\file nuklear.h\n * \\brief main API and documentation file\n *\n * \\details\n */\n#ifndef NK_NUKLEAR_H_\n#define NK_NUKLEAR_H_\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * ==============================================================\n *\n *                          CONSTANTS\n *\n * ===============================================================\n */\n\n#define NK_UNDEFINED (-1.0f)\n#define NK_UTF_INVALID 0xFFFD /**< internal invalid utf8 rune */\n#define NK_UTF_SIZE 4 /**< describes the number of bytes a glyph consists of*/\n#ifndef NK_INPUT_MAX\n  #define NK_INPUT_MAX 16\n#endif\n#ifndef NK_MAX_NUMBER_BUFFER\n  #define NK_MAX_NUMBER_BUFFER 64\n#endif\n#ifndef NK_SCROLLBAR_HIDING_TIMEOUT\n  #define NK_SCROLLBAR_HIDING_TIMEOUT 4.0f\n#endif\n/*\n * ==============================================================\n *\n *                          HELPER\n *\n * ===============================================================\n */\n\n#ifndef NK_API\n  #ifdef NK_PRIVATE\n    #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199409L))\n      #define NK_API static inline\n    #elif defined(__cplusplus)\n      #define NK_API static inline\n    #else\n      #define NK_API static\n    #endif\n  #else\n    #define NK_API extern\n  #endif\n#endif\n#ifndef NK_LIB\n  #ifdef NK_SINGLE_FILE\n    #define NK_LIB static\n  #else\n    #define NK_LIB extern\n  #endif\n#endif\n\n#define NK_INTERN static\n#define NK_STORAGE static\n#define NK_GLOBAL static\n\n#define NK_FLAG(x) (1 << (x))\n#define NK_STRINGIFY(x) #x\n#define NK_MACRO_STRINGIFY(x) NK_STRINGIFY(x)\n#define NK_STRING_JOIN_IMMEDIATE(arg1, arg2) arg1 ## arg2\n#define NK_STRING_JOIN_DELAY(arg1, arg2) NK_STRING_JOIN_IMMEDIATE(arg1, arg2)\n#define NK_STRING_JOIN(arg1, arg2) NK_STRING_JOIN_DELAY(arg1, arg2)\n\n#ifdef _MSC_VER\n  #define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__COUNTER__)\n#else\n  #define NK_UNIQUE_NAME(name) NK_STRING_JOIN(name,__LINE__)\n#endif\n\n#ifndef NK_STATIC_ASSERT\n  #define NK_STATIC_ASSERT(exp) typedef char NK_UNIQUE_NAME(_dummy_array)[(exp)?1:-1]\n#endif\n\n#ifndef NK_FILE_LINE\n#ifdef _MSC_VER\n  #define NK_FILE_LINE __FILE__ \":\" NK_MACRO_STRINGIFY(__COUNTER__)\n#else\n  #define NK_FILE_LINE __FILE__ \":\" NK_MACRO_STRINGIFY(__LINE__)\n#endif\n#endif\n\n#define NK_MIN(a,b) ((a) < (b) ? (a) : (b))\n#define NK_MAX(a,b) ((a) < (b) ? (b) : (a))\n#define NK_CLAMP(i,v,x) (NK_MAX(NK_MIN(v,x), i))\n\n#ifdef NK_INCLUDE_STANDARD_VARARGS\n  #include <stdarg.h>\n  #if defined(_MSC_VER) && (_MSC_VER >= 1600) /* VS 2010 and above */\n    #include <sal.h>\n    #define NK_PRINTF_FORMAT_STRING _Printf_format_string_\n  #else\n    #define NK_PRINTF_FORMAT_STRING\n  #endif\n  #if defined(__GNUC__)\n    #define NK_PRINTF_VARARG_FUNC(fmtargnumber) __attribute__((format(__printf__, fmtargnumber, fmtargnumber+1)))\n    #define NK_PRINTF_VALIST_FUNC(fmtargnumber) __attribute__((format(__printf__, fmtargnumber, 0)))\n  #else\n    #define NK_PRINTF_VARARG_FUNC(fmtargnumber)\n    #define NK_PRINTF_VALIST_FUNC(fmtargnumber)\n  #endif\n#endif\n\n/*\n * ===============================================================\n *\n *                          BASIC\n *\n * ===============================================================\n */\n #ifdef NK_INCLUDE_FIXED_TYPES\n #include <stdint.h>\n #define NK_INT8 int8_t\n #define NK_UINT8 uint8_t\n #define NK_INT16 int16_t\n #define NK_UINT16 uint16_t\n #define NK_INT32 int32_t\n #define NK_UINT32 uint32_t\n #define NK_SIZE_TYPE uintptr_t\n #define NK_POINTER_TYPE uintptr_t\n#else\n  #ifndef NK_INT8\n    #define NK_INT8 signed char\n  #endif\n  #ifndef NK_UINT8\n    #define NK_UINT8 unsigned char\n  #endif\n  #ifndef NK_INT16\n    #define NK_INT16 signed short\n  #endif\n  #ifndef NK_UINT16\n    #define NK_UINT16 unsigned short\n  #endif\n  #ifndef NK_INT32\n    #if defined(_MSC_VER)\n      #define NK_INT32 __int32\n    #else\n      #define NK_INT32 signed int\n    #endif\n  #endif\n  #ifndef NK_UINT32\n    #if defined(_MSC_VER)\n      #define NK_UINT32 unsigned __int32\n    #else\n      #define NK_UINT32 unsigned int\n    #endif\n  #endif\n  #ifndef NK_SIZE_TYPE\n    #if defined(_WIN64) && defined(_MSC_VER)\n      #define NK_SIZE_TYPE unsigned __int64\n    #elif defined(_WIN64) && (defined(__MINGW64__) || defined(__clang__))\n      #define NK_SIZE_TYPE unsigned long long\n    #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)\n      #define NK_SIZE_TYPE unsigned __int32\n    #elif (defined(_WIN32) || defined(WIN32)) && (defined(__MINGW32__) || defined(__clang__))\n      #define NK_SIZE_TYPE unsigned long\n    #elif defined(__GNUC__) || defined(__clang__)\n      #if defined(__x86_64__) || defined(__ppc64__) || defined(__PPC64__) || defined(__aarch64__)\n        #define NK_SIZE_TYPE unsigned long\n      #else\n        #define NK_SIZE_TYPE unsigned int\n      #endif\n    #else\n      #define NK_SIZE_TYPE unsigned long\n    #endif\n  #endif\n  #ifndef NK_POINTER_TYPE\n    #if defined(_WIN64) && defined(_MSC_VER)\n      #define NK_POINTER_TYPE unsigned __int64\n    #elif defined(_WIN64) && (defined(__MINGW64__) || defined(__clang__))\n      #define NK_POINTER_TYPE unsigned long long\n    #elif (defined(_WIN32) || defined(WIN32)) && defined(_MSC_VER)\n      #define NK_POINTER_TYPE unsigned __int32\n    #elif (defined(_WIN32) || defined(WIN32)) && (defined(__MINGW32__) || defined(__clang__))\n      #define NK_POINTER_TYPE unsigned long\n    #elif defined(__GNUC__) || defined(__clang__)\n      #if defined(__x86_64__) || defined(__ppc64__) || defined(__PPC64__) || defined(__aarch64__)\n        #define NK_POINTER_TYPE unsigned long\n      #else\n        #define NK_POINTER_TYPE unsigned int\n      #endif\n    #else\n      #define NK_POINTER_TYPE unsigned long\n    #endif\n  #endif\n#endif\n\n/**< could be any type with semantic of standard bool, either equal or smaller than int */\n#ifndef NK_BOOL\n  #ifdef NK_INCLUDE_STANDARD_BOOL\n    #include <stdbool.h>\n    #define NK_BOOL bool\n  #else\n    #define NK_BOOL int\n  #endif\n#endif\n\ntypedef NK_INT8 nk_char;\ntypedef NK_UINT8 nk_uchar;\ntypedef NK_UINT8 nk_byte;\ntypedef NK_INT16 nk_short;\ntypedef NK_UINT16 nk_ushort;\ntypedef NK_INT32 nk_int;\ntypedef NK_UINT32 nk_uint;\ntypedef NK_SIZE_TYPE nk_size;\ntypedef NK_POINTER_TYPE nk_ptr;\ntypedef NK_BOOL nk_bool;\n\ntypedef nk_uint nk_hash;\ntypedef nk_uint nk_flags;\ntypedef nk_uint nk_rune;\n\n/* Make sure correct type size:\n * This will fire with a negative subscript error if the type sizes\n * are set incorrectly by the compiler, and compile out if not */\nNK_STATIC_ASSERT(sizeof(nk_short) == 2);\nNK_STATIC_ASSERT(sizeof(nk_ushort) == 2);\nNK_STATIC_ASSERT(sizeof(nk_uint) == 4);\nNK_STATIC_ASSERT(sizeof(nk_int) == 4);\nNK_STATIC_ASSERT(sizeof(nk_byte) == 1);\nNK_STATIC_ASSERT(sizeof(nk_flags) >= 4);\nNK_STATIC_ASSERT(sizeof(nk_rune) >= 4);\nNK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*));\nNK_STATIC_ASSERT(sizeof(nk_ptr) >= sizeof(void*));\nNK_STATIC_ASSERT(sizeof(nk_bool) <= sizeof(int));\n\n/* ============================================================================\n *\n *                                  API\n *\n * =========================================================================== */\nstruct nk_buffer;\nstruct nk_allocator;\nstruct nk_command_buffer;\nstruct nk_draw_command;\nstruct nk_convert_config;\nstruct nk_style_item;\nstruct nk_text_edit;\nstruct nk_draw_list;\nstruct nk_user_font;\nstruct nk_panel;\nstruct nk_context;\nstruct nk_draw_vertex_layout_element;\nstruct nk_style_button;\nstruct nk_style_toggle;\nstruct nk_style_selectable;\nstruct nk_style_slide;\nstruct nk_style_progress;\nstruct nk_style_scrollbar;\nstruct nk_style_edit;\nstruct nk_style_property;\nstruct nk_style_chart;\nstruct nk_style_combo;\nstruct nk_style_tab;\nstruct nk_style_window_header;\nstruct nk_style_window;\n\nenum {nk_false, nk_true};\nstruct nk_color {nk_byte r,g,b,a;};\nstruct nk_colorf {float r,g,b,a;};\nstruct nk_vec2 {float x,y;};\nstruct nk_vec2i {short x, y;};\nstruct nk_rect {float x,y,w,h;};\nstruct nk_recti {short x,y,w,h;};\ntypedef char nk_glyph[NK_UTF_SIZE];\ntypedef union {void *ptr; int id;} nk_handle;\nstruct nk_image {nk_handle handle; nk_ushort w, h; nk_ushort region[4];};\nstruct nk_nine_slice {struct nk_image img; nk_ushort l, t, r, b;};\nstruct nk_cursor {struct nk_image img; struct nk_vec2 size, offset;};\nstruct nk_scroll {nk_uint x, y;};\n\n/* Make sure the semantic of nk_true/nk_false is compatible with nk_bool */\nNK_STATIC_ASSERT(!((nk_bool)0) == !(nk_false));\nNK_STATIC_ASSERT(!((nk_bool)1) == !(nk_true));\n\nenum nk_heading         {NK_UP, NK_RIGHT, NK_DOWN, NK_LEFT};\nenum nk_button_behavior {NK_BUTTON_DEFAULT, NK_BUTTON_REPEATER};\nenum nk_modify          {NK_FIXED = nk_false, NK_MODIFIABLE = nk_true};\nenum nk_orientation     {NK_VERTICAL, NK_HORIZONTAL};\nenum nk_collapse_states {NK_MINIMIZED = nk_false, NK_MAXIMIZED = nk_true};\nenum nk_show_states     {NK_HIDDEN = nk_false, NK_SHOWN = nk_true};\nenum nk_chart_type      {NK_CHART_LINES, NK_CHART_COLUMN, NK_CHART_MAX};\nenum nk_chart_event     {NK_CHART_HOVERING = 0x01, NK_CHART_CLICKED = 0x02};\nenum nk_color_format    {NK_RGB, NK_RGBA};\nenum nk_popup_type      {NK_POPUP_STATIC, NK_POPUP_DYNAMIC};\nenum nk_layout_format   {NK_DYNAMIC, NK_STATIC};\nenum nk_tree_type       {NK_TREE_NODE, NK_TREE_TAB};\n\nenum nk_tooltip_pos {\n    NK_TOP_LEFT,\n    NK_TOP_CENTER,\n    NK_TOP_RIGHT,\n\n    NK_MIDDLE_LEFT,\n    NK_MIDDLE_CENTER,\n    NK_MIDDLE_RIGHT,\n\n    NK_BOTTOM_LEFT,\n    NK_BOTTOM_CENTER,\n    NK_BOTTOM_RIGHT\n};\n\ntypedef void*(*nk_plugin_alloc)(nk_handle, void *old, nk_size);\ntypedef void (*nk_plugin_free)(nk_handle, void *old);\ntypedef nk_bool(*nk_plugin_filter)(const struct nk_text_edit*, nk_rune unicode);\ntypedef void(*nk_plugin_paste)(nk_handle, struct nk_text_edit*);\ntypedef void(*nk_plugin_copy)(nk_handle, const char*, int len);\n\nstruct nk_allocator {\n    nk_handle userdata;\n    nk_plugin_alloc alloc;\n    nk_plugin_free free;\n};\nenum nk_symbol_type {\n    NK_SYMBOL_NONE,\n    NK_SYMBOL_X,\n    NK_SYMBOL_UNDERSCORE,\n    NK_SYMBOL_CIRCLE_SOLID,\n    NK_SYMBOL_CIRCLE_OUTLINE,\n    NK_SYMBOL_RECT_SOLID,\n    NK_SYMBOL_RECT_OUTLINE,\n    NK_SYMBOL_TRIANGLE_UP,\n    NK_SYMBOL_TRIANGLE_DOWN,\n    NK_SYMBOL_TRIANGLE_LEFT,\n    NK_SYMBOL_TRIANGLE_RIGHT,\n    NK_SYMBOL_PLUS,\n    NK_SYMBOL_MINUS,\n    NK_SYMBOL_TRIANGLE_UP_OUTLINE,\n    NK_SYMBOL_TRIANGLE_DOWN_OUTLINE,\n    NK_SYMBOL_TRIANGLE_LEFT_OUTLINE,\n    NK_SYMBOL_TRIANGLE_RIGHT_OUTLINE,\n    NK_SYMBOL_MAX\n};\n/* =============================================================================\n *\n *                                  CONTEXT\n *\n * =============================================================================*/\n/**\n * \\page Context\n * Contexts are the main entry point and the majestro of nuklear and contain all required state.\n * They are used for window, memory, input, style, stack, commands and time management and need\n * to be passed into all nuklear GUI specific functions.\n *\n * # Usage\n * To use a context it first has to be initialized which can be achieved by calling\n * one of either `nk_init_default`, `nk_init_fixed`, `nk_init`, `nk_init_custom`.\n * Each takes in a font handle and a specific way of handling memory. Memory control\n * hereby ranges from standard library to just specifying a fixed sized block of memory\n * which nuklear has to manage itself from.\n *\n * ```c\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     // [...]\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n *\n * # Reference\n * Function            | Description\n * --------------------|-------------------------------------------------------\n * \\ref nk_init_default | Initializes context with standard library memory allocation (malloc,free)\n * \\ref nk_init_fixed   | Initializes context from single fixed size memory block\n * \\ref nk_init         | Initializes context with memory allocator callbacks for alloc and free\n * \\ref nk_init_custom  | Initializes context from two buffers. One for draw commands the other for window/panel/table allocations\n * \\ref nk_clear        | Called at the end of the frame to reset and prepare the context for the next frame\n * \\ref nk_free         | Shutdown and free all memory allocated inside the context\n * \\ref nk_set_user_data| Utility function to pass user data to draw command\n */\n\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\n\n/**\n * # nk_init_default\n * Initializes a `nk_context` struct with a default standard library allocator.\n * Should be used if you don't want to be bothered with memory management in nuklear.\n *\n * ```c\n * nk_bool nk_init_default(struct nk_context *ctx, const struct nk_user_font *font);\n * ```\n *\n * Parameter   | Description\n * ------------|---------------------------------------------------------------\n * \\param[in] ctx     | Must point to an either stack or heap allocated `nk_context` struct\n * \\param[in] font    | Must point to a previously initialized font handle for more info look at font documentation\n *\n * \\returns either `false(0)` on failure or `true(1)` on success.\n */\nNK_API nk_bool nk_init_default(struct nk_context*, const struct nk_user_font*);\n#endif\n/**\n * # nk_init_fixed\n * Initializes a `nk_context` struct from single fixed size memory block\n * Should be used if you want complete control over nuklear's memory management.\n * Especially recommended for system with little memory or systems with virtual memory.\n * For the later case you can just allocate for example 16MB of virtual memory\n * and only the required amount of memory will actually be committed.\n *\n * ```c\n * nk_bool nk_init_fixed(struct nk_context *ctx, void *memory, nk_size size, const struct nk_user_font *font);\n * ```\n *\n * !!! Warning\n *     make sure the passed memory block is aligned correctly for `nk_draw_commands`.\n *\n * Parameter   | Description\n * ------------|--------------------------------------------------------------\n * \\param[in] ctx     | Must point to an either stack or heap allocated `nk_context` struct\n * \\param[in] memory  | Must point to a previously allocated memory block\n * \\param[in] size    | Must contain the total size of memory\n * \\param[in] font    | Must point to a previously initialized font handle for more info look at font documentation\n *\n * \\returns either `false(0)` on failure or `true(1)` on success.\n */\nNK_API nk_bool nk_init_fixed(struct nk_context*, void *memory, nk_size size, const struct nk_user_font*);\n\n/**\n * # nk_init\n * Initializes a `nk_context` struct with memory allocation callbacks for nuklear to allocate\n * memory from. Used internally for `nk_init_default` and provides a kitchen sink allocation\n * interface to nuklear. Can be useful for cases like monitoring memory consumption.\n *\n * ```c\n * nk_bool nk_init(struct nk_context *ctx, const struct nk_allocator *alloc, const struct nk_user_font *font);\n * ```\n *\n * Parameter   | Description\n * ------------|---------------------------------------------------------------\n * \\param[in] ctx     | Must point to an either stack or heap allocated `nk_context` struct\n * \\param[in] alloc   | Must point to a previously allocated memory allocator\n * \\param[in] font    | Must point to a previously initialized font handle for more info look at font documentation\n *\n * \\returns either `false(0)` on failure or `true(1)` on success.\n */\nNK_API nk_bool nk_init(struct nk_context*, const struct nk_allocator*, const struct nk_user_font*);\n\n/**\n * \\brief Initializes a `nk_context` struct from two different either fixed or growing buffers.\n *\n * \\details\n * The first buffer is for allocating draw commands while the second buffer is\n * used for allocating windows, panels and state tables.\n *\n * ```c\n * nk_bool nk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font *font);\n * ```\n *\n * \\param[in] ctx    Must point to an either stack or heap allocated `nk_context` struct\n * \\param[in] cmds   Must point to a previously initialized memory buffer either fixed or dynamic to store draw commands into\n * \\param[in] pool   Must point to a previously initialized memory buffer either fixed or dynamic to store windows, panels and tables\n * \\param[in] font   Must point to a previously initialized font handle for more info look at font documentation\n *\n * \\returns either `false(0)` on failure or `true(1)` on success.\n */\nNK_API nk_bool nk_init_custom(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *pool, const struct nk_user_font*);\n\n/**\n * \\brief Resets the context state at the end of the frame.\n *\n * \\details\n * This includes mostly garbage collector tasks like removing windows or table\n * not called and therefore used anymore.\n *\n * ```c\n * void nk_clear(struct nk_context *ctx);\n * ```\n *\n * \\param[in] ctx  Must point to a previously initialized `nk_context` struct\n */\nNK_API void nk_clear(struct nk_context*);\n\n/**\n * \\brief Frees all memory allocated by nuklear; Not needed if context was initialized with `nk_init_fixed`.\n *\n * \\details\n * ```c\n * void nk_free(struct nk_context *ctx);\n * ```\n *\n * \\param[in] ctx  Must point to a previously initialized `nk_context` struct\n */\nNK_API void nk_free(struct nk_context*);\n\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n/**\n * \\brief Sets the currently passed userdata passed down into each draw command.\n *\n * \\details\n * ```c\n * void nk_set_user_data(struct nk_context *ctx, nk_handle data);\n * ```\n *\n * \\param[in] ctx Must point to a previously initialized `nk_context` struct\n * \\param[in] data  Handle with either pointer or index to be passed into every draw commands\n */\nNK_API void nk_set_user_data(struct nk_context*, nk_handle handle);\n#endif\n/* =============================================================================\n *\n *                                  INPUT\n *\n * =============================================================================*/\n/**\n * \\page Input\n *\n * The input API is responsible for holding the current input state composed of\n * mouse, key and text input states.\n * It is worth noting that no direct OS or window handling is done in nuklear.\n * Instead all input state has to be provided by platform specific code. This on one hand\n * expects more work from the user and complicates usage but on the other hand\n * provides simple abstraction over a big number of platforms, libraries and other\n * already provided functionality.\n *\n * ```c\n * nk_input_begin(&ctx);\n * while (GetEvent(&evt)) {\n *     if (evt.type == MOUSE_MOVE)\n *         nk_input_motion(&ctx, evt.motion.x, evt.motion.y);\n *     else if (evt.type == [...]) {\n *         // [...]\n *     }\n * } nk_input_end(&ctx);\n * ```\n *\n * # Usage\n * Input state needs to be provided to nuklear by first calling `nk_input_begin`\n * which resets internal state like delta mouse position and button transitions.\n * After `nk_input_begin` all current input state needs to be provided. This includes\n * mouse motion, button and key pressed and released, text input and scrolling.\n * Both event- or state-based input handling are supported by this API\n * and should work without problems. Finally after all input state has been\n * mirrored `nk_input_end` needs to be called to finish input process.\n *\n * ```c\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     Event evt;\n *     nk_input_begin(&ctx);\n *     while (GetEvent(&evt)) {\n *         if (evt.type == MOUSE_MOVE)\n *             nk_input_motion(&ctx, evt.motion.x, evt.motion.y);\n *         else if (evt.type == [...]) {\n *             // [...]\n *         }\n *     }\n *     nk_input_end(&ctx);\n *     // [...]\n *     nk_clear(&ctx);\n * } nk_free(&ctx);\n * ```\n *\n * # Reference\n * Function            | Description\n * --------------------|-------------------------------------------------------\n * \\ref nk_input_begin  | Begins the input mirroring process. Needs to be called before all other `nk_input_xxx` calls\n * \\ref nk_input_motion | Mirrors mouse cursor position\n * \\ref nk_input_key    | Mirrors key state with either pressed or released\n * \\ref nk_input_button | Mirrors mouse button state with either pressed or released\n * \\ref nk_input_scroll | Mirrors mouse scroll values\n * \\ref nk_input_char   | Adds a single ASCII text character into an internal text buffer\n * \\ref nk_input_glyph  | Adds a single multi-byte UTF-8 character into an internal text buffer\n * \\ref nk_input_unicode| Adds a single unicode rune into an internal text buffer\n * \\ref nk_input_end    | Ends the input mirroring process by calculating state changes. Don't call any `nk_input_xxx` function referenced above after this call\n */\n\nenum nk_keys {\n    NK_KEY_NONE,\n    NK_KEY_SHIFT,\n    NK_KEY_CTRL,\n    NK_KEY_DEL,\n    NK_KEY_ENTER,\n    NK_KEY_TAB,\n    NK_KEY_BACKSPACE,\n    NK_KEY_COPY,\n    NK_KEY_CUT,\n    NK_KEY_PASTE,\n    NK_KEY_UP,\n    NK_KEY_DOWN,\n    NK_KEY_LEFT,\n    NK_KEY_RIGHT,\n    /* Shortcuts: text field */\n    NK_KEY_TEXT_INSERT_MODE,\n    NK_KEY_TEXT_REPLACE_MODE,\n    NK_KEY_TEXT_RESET_MODE,\n    NK_KEY_TEXT_LINE_START,\n    NK_KEY_TEXT_LINE_END,\n    NK_KEY_TEXT_START,\n    NK_KEY_TEXT_END,\n    NK_KEY_TEXT_UNDO,\n    NK_KEY_TEXT_REDO,\n    NK_KEY_TEXT_SELECT_ALL,\n    NK_KEY_TEXT_WORD_LEFT,\n    NK_KEY_TEXT_WORD_RIGHT,\n    /* Shortcuts: scrollbar */\n    NK_KEY_SCROLL_START,\n    NK_KEY_SCROLL_END,\n    NK_KEY_SCROLL_DOWN,\n    NK_KEY_SCROLL_UP,\n    NK_KEY_MAX\n};\nenum nk_buttons {\n    NK_BUTTON_LEFT,\n    NK_BUTTON_MIDDLE,\n    NK_BUTTON_RIGHT,\n    NK_BUTTON_DOUBLE, /* Double click of the Left mouse button. */\n    NK_BUTTON_X1, /* Commonly used for \"Back\" in UI navigation. Mouse Button 4. */\n    NK_BUTTON_X2, /* Commonly used for \"Forward\" in UI navigation. Mouse Button 5. */\n    NK_BUTTON_MAX\n};\n\n/**\n * \\brief Begins the input mirroring process by resetting text, scroll\n * mouse, previous mouse position and movement as well as key state transitions.\n *\n * \\details\n * ```c\n * void nk_input_begin(struct nk_context*);\n * ```\n *\n * \\param[in] ctx Must point to a previously initialized `nk_context` struct\n */\nNK_API void nk_input_begin(struct nk_context*);\n\n/**\n * \\brief Mirrors current mouse position to nuklear\n *\n * \\details\n * ```c\n * void nk_input_motion(struct nk_context *ctx, int x, int y);\n * ```\n *\n * \\param[in] ctx   Must point to a previously initialized `nk_context` struct\n * \\param[in] x     Must hold an integer describing the current mouse cursor x-position\n * \\param[in] y     Must hold an integer describing the current mouse cursor y-position\n */\nNK_API void nk_input_motion(struct nk_context*, int x, int y);\n\n/**\n * \\brief Mirrors the state of a specific key to nuklear\n *\n * \\details\n * ```c\n * void nk_input_key(struct nk_context*, enum nk_keys key, nk_bool down);\n * ```\n *\n * \\param[in] ctx      Must point to a previously initialized `nk_context` struct\n * \\param[in] key      Must be any value specified in enum `nk_keys` that needs to be mirrored\n * \\param[in] down     Must be 0 for key is up and 1 for key is down\n */\nNK_API void nk_input_key(struct nk_context*, enum nk_keys, nk_bool down);\n\n/**\n * \\brief Mirrors the state of a specific mouse button to nuklear\n *\n * \\details\n * ```c\n * void nk_input_button(struct nk_context *ctx, enum nk_buttons btn, int x, int y, nk_bool down);\n * ```\n *\n * \\param[in] ctx     Must point to a previously initialized `nk_context` struct\n * \\param[in] btn     Must be any value specified in enum `nk_buttons` that needs to be mirrored\n * \\param[in] x       Must contain an integer describing mouse cursor x-position on click up/down\n * \\param[in] y       Must contain an integer describing mouse cursor y-position on click up/down\n * \\param[in] down    Must be 0 for key is up and 1 for key is down\n */\nNK_API void nk_input_button(struct nk_context*, enum nk_buttons, int x, int y, nk_bool down);\n\n/**\n * \\brief Copies the last mouse scroll value to nuklear.\n *\n * \\details\n * Is generally a scroll value. So does not have to come from mouse and could\n * also originate from balls, tracks, linear guide rails, or other programs.\n *\n * ```c\n * void nk_input_scroll(struct nk_context *ctx, struct nk_vec2 val);\n * ```\n *\n * \\param[in] ctx     | Must point to a previously initialized `nk_context` struct\n * \\param[in] val     | vector with both X- as well as Y-scroll value\n */\nNK_API void nk_input_scroll(struct nk_context*, struct nk_vec2 val);\n\n/**\n * \\brief Copies a single ASCII character into an internal text buffer\n *\n * \\details\n * This is basically a helper function to quickly push ASCII characters into\n * nuklear.\n *\n * \\note\n *     Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`.\n *\n * ```c\n * void nk_input_char(struct nk_context *ctx, char c);\n * ```\n *\n * \\param[in] ctx     | Must point to a previously initialized `nk_context` struct\n * \\param[in] c       | Must be a single ASCII character preferable one that can be printed\n */\nNK_API void nk_input_char(struct nk_context*, char);\n\n/**\n * \\brief Converts an encoded unicode rune into UTF-8 and copies the result into an\n * internal text buffer.\n *\n * \\note\n *     Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`.\n *\n * ```c\n * void nk_input_glyph(struct nk_context *ctx, const nk_glyph g);\n * ```\n *\n * \\param[in] ctx     | Must point to a previously initialized `nk_context` struct\n * \\param[in] g       | UTF-32 unicode codepoint\n */\nNK_API void nk_input_glyph(struct nk_context*, const nk_glyph);\n\n/**\n * \\brief Converts a unicode rune into UTF-8 and copies the result\n * into an internal text buffer.\n *\n * \\details\n * \\note\n *     Stores up to NK_INPUT_MAX bytes between `nk_input_begin` and `nk_input_end`.\n *\n * ```c\n * void nk_input_unicode(struct nk_context*, nk_rune rune);\n * ```\n *\n * \\param[in] ctx     | Must point to a previously initialized `nk_context` struct\n * \\param[in] rune    | UTF-32 unicode codepoint\n */\nNK_API void nk_input_unicode(struct nk_context*, nk_rune);\n\n/**\n * \\brief End the input mirroring process by resetting mouse grabbing\n * state to ensure the mouse cursor is not grabbed indefinitely.\n *\n * \\details\n * ```c\n * void nk_input_end(struct nk_context *ctx);\n * ```\n *\n * \\param[in] ctx     | Must point to a previously initialized `nk_context` struct\n */\nNK_API void nk_input_end(struct nk_context*);\n\n/* =============================================================================\n *\n *                                  DRAWING\n *\n * =============================================================================*/\n/**\n * \\page Drawing\n * This library was designed to be render backend agnostic so it does\n * not draw anything to screen directly. Instead all drawn shapes, widgets\n * are made of, are buffered into memory and make up a command queue.\n * Each frame therefore fills the command buffer with draw commands\n * that then need to be executed by the user and his own render backend.\n * After that the command buffer needs to be cleared and a new frame can be\n * started. It is probably important to note that the command buffer is the main\n * drawing API and the optional vertex buffer API only takes this format and\n * converts it into a hardware accessible format.\n *\n * # Usage\n * To draw all draw commands accumulated over a frame you need your own render\n * backend able to draw a number of 2D primitives. This includes at least\n * filled and stroked rectangles, circles, text, lines, triangles and scissors.\n * As soon as this criterion is met you can iterate over each draw command\n * and execute each draw command in a interpreter like fashion:\n *\n * ```c\n * const struct nk_command *cmd = 0;\n * nk_foreach(cmd, &ctx) {\n *     switch (cmd->type) {\n *     case NK_COMMAND_LINE:\n *         your_draw_line_function(...)\n *         break;\n *     case NK_COMMAND_RECT\n *         your_draw_rect_function(...)\n *         break;\n *     case //...:\n *         //[...]\n *     }\n * }\n * ```\n *\n * In program flow context draw commands need to be executed after input has been\n * gathered and the complete UI with windows and their contained widgets have\n * been executed and before calling `nk_clear` which frees all previously\n * allocated draw commands.\n *\n * ```c\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     Event evt;\n *     nk_input_begin(&ctx);\n *     while (GetEvent(&evt)) {\n *         if (evt.type == MOUSE_MOVE)\n *             nk_input_motion(&ctx, evt.motion.x, evt.motion.y);\n *         else if (evt.type == [...]) {\n *             [...]\n *         }\n *     }\n *     nk_input_end(&ctx);\n *     //\n *     // [...]\n *     //\n *     const struct nk_command *cmd = 0;\n *     nk_foreach(cmd, &ctx) {\n *     switch (cmd->type) {\n *     case NK_COMMAND_LINE:\n *         your_draw_line_function(...)\n *         break;\n *     case NK_COMMAND_RECT\n *         your_draw_rect_function(...)\n *         break;\n *     case ...:\n *         // [...]\n *     }\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n *\n * You probably noticed that you have to draw all of the UI each frame which is\n * quite wasteful. While the actual UI updating loop is quite fast rendering\n * without actually needing it is not. So there are multiple things you could do.\n *\n * First is only update on input. This of course is only an option if your\n * application only depends on the UI and does not require any outside calculations.\n * If you actually only update on input make sure to update the UI two times each\n * frame and call `nk_clear` directly after the first pass and only draw in\n * the second pass. In addition it is recommended to also add additional timers\n * to make sure the UI is not drawn more than a fixed number of frames per second.\n *\n * ```c\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     // [...wait for input ]\n *     // [...do two UI passes ...]\n *     do_ui(...)\n *     nk_clear(&ctx);\n *     do_ui(...)\n *     //\n *     // draw\n *     const struct nk_command *cmd = 0;\n *     nk_foreach(cmd, &ctx) {\n *     switch (cmd->type) {\n *     case NK_COMMAND_LINE:\n *         your_draw_line_function(...)\n *         break;\n *     case NK_COMMAND_RECT\n *         your_draw_rect_function(...)\n *         break;\n *     case ...:\n *         //[...]\n *     }\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n *\n * The second probably more applicable trick is to only draw if anything changed.\n * It is not really useful for applications with continuous draw loop but\n * quite useful for desktop applications. To actually get nuklear to only\n * draw on changes you first have to define `NK_ZERO_COMMAND_MEMORY` and\n * allocate a memory buffer that will store each unique drawing output.\n * After each frame you compare the draw command memory inside the library\n * with your allocated buffer by memcmp. If memcmp detects differences\n * you have to copy the command buffer into the allocated buffer\n * and then draw like usual (this example uses fixed memory but you could\n * use dynamically allocated memory).\n *\n * ```c\n * //[... other defines ...]\n * #define NK_ZERO_COMMAND_MEMORY\n * #include \"nuklear.h\"\n * //\n * // setup context\n * struct nk_context ctx;\n * void *last = calloc(1,64*1024);\n * void *buf = calloc(1,64*1024);\n * nk_init_fixed(&ctx, buf, 64*1024);\n * //\n * // loop\n * while (1) {\n *     // [...input...]\n *     // [...ui...]\n *     void *cmds = nk_buffer_memory(&ctx.memory);\n *     if (memcmp(cmds, last, ctx.memory.allocated)) {\n *         memcpy(last,cmds,ctx.memory.allocated);\n *         const struct nk_command *cmd = 0;\n *         nk_foreach(cmd, &ctx) {\n *             switch (cmd->type) {\n *             case NK_COMMAND_LINE:\n *                 your_draw_line_function(...)\n *                 break;\n *             case NK_COMMAND_RECT\n *                 your_draw_rect_function(...)\n *                 break;\n *             case ...:\n *                 // [...]\n *             }\n *         }\n *     }\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n *\n * Finally while using draw commands makes sense for higher abstracted platforms like\n * X11 and Win32 or drawing libraries it is often desirable to use graphics\n * hardware directly. Therefore it is possible to just define\n * `NK_INCLUDE_VERTEX_BUFFER_OUTPUT` which includes optional vertex output.\n * To access the vertex output you first have to convert all draw commands into\n * vertexes by calling `nk_convert` which takes in your preferred vertex format.\n * After successfully converting all draw commands just iterate over and execute all\n * vertex draw commands:\n *\n * ```c\n * // fill configuration\n * struct your_vertex\n * {\n *     float pos[2]; // important to keep it to 2 floats\n *     float uv[2];\n *     unsigned char col[4];\n * };\n * struct nk_convert_config cfg = {};\n * static const struct nk_draw_vertex_layout_element vertex_layout[] = {\n *     {NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, pos)},\n *     {NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(struct your_vertex, uv)},\n *     {NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(struct your_vertex, col)},\n *     {NK_VERTEX_LAYOUT_END}\n * };\n * cfg.shape_AA = NK_ANTI_ALIASING_ON;\n * cfg.line_AA = NK_ANTI_ALIASING_ON;\n * cfg.vertex_layout = vertex_layout;\n * cfg.vertex_size = sizeof(struct your_vertex);\n * cfg.vertex_alignment = NK_ALIGNOF(struct your_vertex);\n * cfg.circle_segment_count = 22;\n * cfg.curve_segment_count = 22;\n * cfg.arc_segment_count = 22;\n * cfg.global_alpha = 1.0f;\n * cfg.tex_null = dev->tex_null;\n * //\n * // setup buffers and convert\n * struct nk_buffer cmds, verts, idx;\n * nk_buffer_init_default(&cmds);\n * nk_buffer_init_default(&verts);\n * nk_buffer_init_default(&idx);\n * nk_convert(&ctx, &cmds, &verts, &idx, &cfg);\n * //\n * // draw\n * nk_draw_foreach(cmd, &ctx, &cmds) {\n * if (!cmd->elem_count) continue;\n *     //[...]\n * }\n * nk_buffer_free(&cms);\n * nk_buffer_free(&verts);\n * nk_buffer_free(&idx);\n * ```\n *\n * # Reference\n * Function            | Description\n * --------------------|-------------------------------------------------------\n * \\ref nk__begin       | Returns the first draw command in the context draw command list to be drawn\n * \\ref nk__next        | Increments the draw command iterator to the next command inside the context draw command list\n * \\ref nk_foreach      | Iterates over each draw command inside the context draw command list\n * \\ref nk_convert      | Converts from the abstract draw commands list into a hardware accessible vertex format\n * \\ref nk_draw_begin   | Returns the first vertex command in the context vertex draw list to be executed\n * \\ref nk__draw_next   | Increments the vertex command iterator to the next command inside the context vertex command list\n * \\ref nk__draw_end    | Returns the end of the vertex draw list\n * \\ref nk_draw_foreach | Iterates over each vertex draw command inside the vertex draw list\n */\n\nenum nk_anti_aliasing {NK_ANTI_ALIASING_OFF, NK_ANTI_ALIASING_ON};\nenum nk_convert_result {\n    NK_CONVERT_SUCCESS = 0,\n    NK_CONVERT_INVALID_PARAM = 1,\n    NK_CONVERT_COMMAND_BUFFER_FULL = NK_FLAG(1),\n    NK_CONVERT_VERTEX_BUFFER_FULL = NK_FLAG(2),\n    NK_CONVERT_ELEMENT_BUFFER_FULL = NK_FLAG(3)\n};\nstruct nk_draw_null_texture {\n    nk_handle texture; /**!< texture handle to a texture with a white pixel */\n    struct nk_vec2 uv; /**!< coordinates to a white pixel in the texture  */\n};\nstruct nk_convert_config {\n    float global_alpha;             /**!< global alpha value */\n    enum nk_anti_aliasing line_AA;  /**!< line anti-aliasing flag can be turned off if you are tight on memory */\n    enum nk_anti_aliasing shape_AA; /**!< shape anti-aliasing flag can be turned off if you are tight on memory */\n    unsigned circle_segment_count;  /**!< number of segments used for circles: default to 22 */\n    unsigned arc_segment_count;     /**!< number of segments used for arcs: default to 22 */\n    unsigned curve_segment_count;   /**!< number of segments used for curves: default to 22 */\n    struct nk_draw_null_texture tex_null; /**!< handle to texture with a white pixel for shape drawing */\n    const struct nk_draw_vertex_layout_element *vertex_layout; /**!< describes the vertex output format and packing */\n    nk_size vertex_size;      /**!< sizeof one vertex for vertex packing */\n    nk_size vertex_alignment; /**!< vertex alignment: Can be obtained by NK_ALIGNOF */\n};\n\n/**\n * \\brief Returns a draw command list iterator to iterate all draw\n * commands accumulated over one frame.\n *\n * \\details\n * ```c\n * const struct nk_command* nk__begin(struct nk_context*);\n * ```\n *\n * \\param[in] ctx     | must point to an previously initialized `nk_context` struct at the end of a frame\n *\n * \\returns draw command pointer pointing to the first command inside the draw command list\n */\nNK_API const struct nk_command* nk__begin(struct nk_context*);\n\n/**\n * \\brief Returns draw command pointer pointing to the next command inside the draw command list\n *\n * \\details\n * ```c\n * const struct nk_command* nk__next(struct nk_context*, const struct nk_command*);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct at the end of a frame\n * \\param[in] cmd     | Must point to an previously a draw command either returned by `nk__begin` or `nk__next`\n *\n * \\returns draw command pointer pointing to the next command inside the draw command list\n */\nNK_API const struct nk_command* nk__next(struct nk_context*, const struct nk_command*);\n\n/**\n * \\brief Iterates over each draw command inside the context draw command list\n *\n * ```c\n * #define nk_foreach(c, ctx)\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct at the end of a frame\n * \\param[in] cmd     | Command pointer initialized to NULL\n */\n#define nk_foreach(c, ctx) for((c) = nk__begin(ctx); (c) != 0; (c) = nk__next(ctx,c))\n\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n\n/**\n * \\brief Converts all internal draw commands into vertex draw commands and fills\n * three buffers with vertexes, vertex draw commands and vertex indices.\n *\n * \\details\n * The vertex format as well as some other configuration values have to be\n * configured by filling out a `nk_convert_config` struct.\n *\n * ```c\n * nk_flags nk_convert(struct nk_context *ctx, struct nk_buffer *cmds,\n *     struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*);\n * ```\n *\n * \\param[in] ctx      Must point to an previously initialized `nk_context` struct at the end of a frame\n * \\param[out] cmds     Must point to a previously initialized buffer to hold converted vertex draw commands\n * \\param[out] vertices Must point to a previously initialized buffer to hold all produced vertices\n * \\param[out] elements Must point to a previously initialized buffer to hold all produced vertex indices\n * \\param[in] config   Must point to a filled out `nk_config` struct to configure the conversion process\n *\n * \\returns one of enum nk_convert_result error codes\n *\n * Parameter                       | Description\n * --------------------------------|-----------------------------------------------------------\n * NK_CONVERT_SUCCESS              | Signals a successful draw command to vertex buffer conversion\n * NK_CONVERT_INVALID_PARAM        | An invalid argument was passed in the function call\n * NK_CONVERT_COMMAND_BUFFER_FULL  | The provided buffer for storing draw commands is full or failed to allocate more memory\n * NK_CONVERT_VERTEX_BUFFER_FULL   | The provided buffer for storing vertices is full or failed to allocate more memory\n * NK_CONVERT_ELEMENT_BUFFER_FULL  | The provided buffer for storing indices is full or failed to allocate more memory\n */\nNK_API nk_flags nk_convert(struct nk_context*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, const struct nk_convert_config*);\n\n/**\n * \\brief Returns a draw vertex command buffer iterator to iterate over the vertex draw command buffer\n *\n * \\details\n * ```c\n * const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct at the end of a frame\n * \\param[in] buf     | Must point to an previously by `nk_convert` filled out vertex draw command buffer\n *\n * \\returns vertex draw command pointer pointing to the first command inside the vertex draw command buffer\n */\nNK_API const struct nk_draw_command* nk__draw_begin(const struct nk_context*, const struct nk_buffer*);\n\n/**\n\n * # # nk__draw_end\n * \\returns the vertex draw command at the end of the vertex draw command buffer\n *\n * ```c\n * const struct nk_draw_command* nk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buf);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct at the end of a frame\n * \\param[in] buf     | Must point to an previously by `nk_convert` filled out vertex draw command buffer\n *\n * \\returns vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer\n\n */\nNK_API const struct nk_draw_command* nk__draw_end(const struct nk_context*, const struct nk_buffer*);\n\n/**\n * # # nk__draw_next\n * Increments the vertex draw command buffer iterator\n *\n * ```c\n * const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] cmd     | Must point to an previously either by `nk__draw_begin` or `nk__draw_next` returned vertex draw command\n * \\param[in] buf     | Must point to an previously by `nk_convert` filled out vertex draw command buffer\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct at the end of a frame\n *\n * \\returns vertex draw command pointer pointing to the end of the last vertex draw command inside the vertex draw command buffer\n\n */\nNK_API const struct nk_draw_command* nk__draw_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_context*);\n\n/**\n * # # nk_draw_foreach\n * Iterates over each vertex draw command inside a vertex draw command buffer\n *\n * ```c\n * #define nk_draw_foreach(cmd,ctx, b)\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] cmd     | `nk_draw_command`iterator set to NULL\n * \\param[in] buf     | Must point to an previously by `nk_convert` filled out vertex draw command buffer\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct at the end of a frame\n */\n\n#define nk_draw_foreach(cmd,ctx, b) for((cmd)=nk__draw_begin(ctx, b); (cmd)!=0; (cmd)=nk__draw_next(cmd, b, ctx))\n#endif\n\n/* =============================================================================\n *\n *                                  WINDOW\n *\n * =============================================================================*/\n/**\n * \\page Window\n * Windows are the main persistent state used inside nuklear and are life time\n * controlled by simply \"retouching\" (i.e.\\ calling) each window each frame.\n * All widgets inside nuklear can only be added inside the function pair `nk_begin_xxx`\n * and `nk_end`. Calling any widgets outside these two functions will result in an\n * assert in debug or no state change in release mode.<br /><br />\n *\n * Each window holds frame persistent state like position, size, flags, state tables,\n * and some garbage collected internal persistent widget state. Each window\n * is linked into a window stack list which determines the drawing and overlapping\n * order. The topmost window thereby is the currently active window.<br /><br />\n *\n * To change window position inside the stack occurs either automatically by\n * user input by being clicked on or programmatically by calling `nk_window_focus`.\n * Windows by default are visible unless explicitly being defined with flag\n * `NK_WINDOW_HIDDEN`, the user clicked the close button on windows with flag\n * `NK_WINDOW_CLOSABLE` or if a window was explicitly hidden by calling\n * `nk_window_show`. To explicitly close and destroy a window call `nk_window_close`.<br /><br />\n *\n * # Usage\n * To create and keep a window you have to call one of the two `nk_begin_xxx`\n * functions to start window declarations and `nk_end` at the end. Furthermore it\n * is recommended to check the return value of `nk_begin_xxx` and only process\n * widgets inside the window if the value is not 0. Either way you have to call\n * `nk_end` at the end of window declarations. Furthermore, do not attempt to\n * nest `nk_begin_xxx` calls which will hopefully result in an assert or if not\n * in a segmentation fault.\n *\n * ```c\n * if (nk_begin_xxx(...) {\n *     // [... widgets ...]\n * }\n * nk_end(ctx);\n * ```\n *\n * In the grand concept window and widget declarations need to occur after input\n * handling and before drawing to screen. Not doing so can result in higher\n * latency or at worst invalid behavior. Furthermore make sure that `nk_clear`\n * is called at the end of the frame. While nuklear's default platform backends\n * already call `nk_clear` for you if you write your own backend not calling\n * `nk_clear` can cause asserts or even worse undefined behavior.\n *\n * ```c\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     Event evt;\n *     nk_input_begin(&ctx);\n *     while (GetEvent(&evt)) {\n *         if (evt.type == MOUSE_MOVE)\n *             nk_input_motion(&ctx, evt.motion.x, evt.motion.y);\n *         else if (evt.type == [...]) {\n *             nk_input_xxx(...);\n *         }\n *     }\n *     nk_input_end(&ctx);\n *\n *     if (nk_begin_xxx(...) {\n *         //[...]\n *     }\n *     nk_end(ctx);\n *\n *     const struct nk_command *cmd = 0;\n *     nk_foreach(cmd, &ctx) {\n *     case NK_COMMAND_LINE:\n *         your_draw_line_function(...)\n *         break;\n *     case NK_COMMAND_RECT\n *         your_draw_rect_function(...)\n *         break;\n *     case //...:\n *         //[...]\n *     }\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n *\n * # Reference\n * Function                                 | Description\n * -----------------------------------------|----------------------------------------\n * \\ref nk_begin                            | Starts a new window; needs to be called every frame for every window (unless hidden) or otherwise the window gets removed\n * \\ref nk_begin_titled                     | Extended window start with separated title and identifier to allow multiple windows with same name but not title\n * \\ref nk_end                              | Needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup\n *\n * Function                                 | Description\n * -----------------------------------------|----------------------------------------\n * \\ref nk_window_find                      | Finds and returns the window with give name\n * \\ref nk_window_get_bounds                | Returns a rectangle with screen position and size of the currently processed window.\n * \\ref nk_window_get_position              | Returns the position of the currently processed window\n * \\ref nk_window_get_size                  | Returns the size with width and height of the currently processed window\n * \\ref nk_window_get_width                 | Returns the width of the currently processed window\n * \\ref nk_window_get_height                | Returns the height of the currently processed window\n * \\ref nk_window_get_panel                 | Returns the underlying panel which contains all processing state of the current window\n * \\ref nk_window_get_content_region        | Returns the position and size of the currently visible and non-clipped space inside the currently processed window\n * \\ref nk_window_get_content_region_min    | Returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window\n * \\ref nk_window_get_content_region_max    | Returns the upper rectangle position of the currently visible and non-clipped space inside the currently processed window\n * \\ref nk_window_get_content_region_size   | Returns the size of the currently visible and non-clipped space inside the currently processed window\n * \\ref nk_window_get_canvas                | Returns the draw command buffer. Can be used to draw custom widgets\n * \\ref nk_window_get_scroll                | Gets the scroll offset of the current window\n * \\ref nk_window_has_focus                 | Returns if the currently processed window is currently active\n * \\ref nk_window_is_collapsed              | Returns if the window with given name is currently minimized/collapsed\n * \\ref nk_window_is_closed                 | Returns if the currently processed window was closed\n * \\ref nk_window_is_hidden                 | Returns if the currently processed window was hidden\n * \\ref nk_window_is_active                 | Same as nk_window_has_focus for some reason\n * \\ref nk_window_is_hovered                | Returns if the currently processed window is currently being hovered by mouse\n * \\ref nk_window_is_any_hovered            | Return if any window currently hovered\n * \\ref nk_item_is_any_active               | Returns if any window or widgets is currently hovered or active\n *\n * Function                                 | Description\n * -----------------------------------------|----------------------------------------\n * \\ref nk_window_set_bounds                | Updates position and size of the currently processed window\n * \\ref nk_window_set_position              | Updates position of the currently process window\n * \\ref nk_window_set_size                  | Updates the size of the currently processed window\n * \\ref nk_window_set_focus                 | Set the currently processed window as active window\n * \\ref nk_window_set_scroll                | Sets the scroll offset of the current window\n *\n * Function                                 | Description\n * -----------------------------------------|----------------------------------------\n * \\ref nk_window_close                     | Closes the window with given window name which deletes the window at the end of the frame\n * \\ref nk_window_collapse                  | Collapses the window with given window name\n * \\ref nk_window_collapse_if               | Collapses the window with given window name if the given condition was met\n * \\ref nk_window_show                      | Hides a visible or reshows a hidden window\n * \\ref nk_window_show_if                   | Hides/shows a window depending on condition\n\n * # nk_panel_flags\n * Flag                        | Description\n * ----------------------------|----------------------------------------\n * NK_WINDOW_BORDER            | Draws a border around the window to visually separate window from the background\n * NK_WINDOW_MOVABLE           | The movable flag indicates that a window can be moved by user input or by dragging the window header\n * NK_WINDOW_SCALABLE          | The scalable flag indicates that a window can be scaled by user input by dragging a scaler icon at the button of the window\n * NK_WINDOW_CLOSABLE          | Adds a closable icon into the header\n * NK_WINDOW_MINIMIZABLE       | Adds a minimize icon into the header\n * NK_WINDOW_NO_SCROLLBAR      | Removes the scrollbar from the window\n * NK_WINDOW_TITLE             | Forces a header at the top at the window showing the title\n * NK_WINDOW_SCROLL_AUTO_HIDE  | Automatically hides the window scrollbar if no user interaction: also requires delta time in `nk_context` to be set each frame\n * NK_WINDOW_BACKGROUND        | Always keep window in the background\n * NK_WINDOW_SCALE_LEFT        | Puts window scaler in the left-bottom corner instead right-bottom\n * NK_WINDOW_NO_INPUT          | Prevents window of scaling, moving or getting focus\n *\n * # nk_collapse_states\n * State           | Description\n * ----------------|-----------------------------------------------------------\n * NK_MINIMIZED| UI section is collapsed and not visible until maximized\n * NK_MAXIMIZED| UI section is extended and visible until minimized\n */\n\nenum nk_panel_flags {\n    NK_WINDOW_BORDER            = NK_FLAG(0),\n    NK_WINDOW_MOVABLE           = NK_FLAG(1),\n    NK_WINDOW_SCALABLE          = NK_FLAG(2),\n    NK_WINDOW_CLOSABLE          = NK_FLAG(3),\n    NK_WINDOW_MINIMIZABLE       = NK_FLAG(4),\n    NK_WINDOW_NO_SCROLLBAR      = NK_FLAG(5),\n    NK_WINDOW_TITLE             = NK_FLAG(6),\n    NK_WINDOW_SCROLL_AUTO_HIDE  = NK_FLAG(7),\n    NK_WINDOW_BACKGROUND        = NK_FLAG(8),\n    NK_WINDOW_SCALE_LEFT        = NK_FLAG(9),\n    NK_WINDOW_NO_INPUT          = NK_FLAG(10)\n};\n\n/**\n * # # nk_begin\n * Starts a new window; needs to be called every frame for every\n * window (unless hidden) or otherwise the window gets removed\n *\n * ```c\n * nk_bool nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] title   | Window title and identifier. Needs to be persistent over frames to identify the window\n * \\param[in] bounds  | Initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame\n * \\param[in] flags   | Window flags defined in the nk_panel_flags section with a number of different window behaviors\n *\n * \\returns `true(1)` if the window can be filled up with widgets from this point\n * until `nk_end` or `false(0)` otherwise for example if minimized\n\n */\nNK_API nk_bool nk_begin(struct nk_context *ctx, const char *title, struct nk_rect bounds, nk_flags flags);\n\n/**\n * # # nk_begin_titled\n * Extended window start with separated title and identifier to allow multiple\n * windows with same title but not name\n *\n * ```c\n * nk_bool nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Window identifier. Needs to be persistent over frames to identify the window\n * \\param[in] title   | Window title displayed inside header if flag `NK_WINDOW_TITLE` or either `NK_WINDOW_CLOSABLE` or `NK_WINDOW_MINIMIZED` was set\n * \\param[in] bounds  | Initial position and window size. However if you do not define `NK_WINDOW_SCALABLE` or `NK_WINDOW_MOVABLE` you can set window position and size every frame\n * \\param[in] flags   | Window flags defined in the nk_panel_flags section with a number of different window behaviors\n *\n * \\returns `true(1)` if the window can be filled up with widgets from this point\n * until `nk_end` or `false(0)` otherwise for example if minimized\n\n */\nNK_API nk_bool nk_begin_titled(struct nk_context *ctx, const char *name, const char *title, struct nk_rect bounds, nk_flags flags);\n\n/**\n * # # nk_end\n * Needs to be called at the end of the window building process to process scaling, scrollbars and general cleanup.\n * All widget calls after this functions will result in asserts or no state changes\n *\n * ```c\n * void nk_end(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n\n */\nNK_API void nk_end(struct nk_context *ctx);\n\n/**\n * # # nk_window_find\n * Finds and returns a window from passed name\n *\n * ```c\n * struct nk_window *nk_window_find(struct nk_context *ctx, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Window identifier\n *\n * \\returns a `nk_window` struct pointing to the identified window or NULL if\n * no window with the given name was found\n */\nNK_API struct nk_window *nk_window_find(const struct nk_context *ctx, const char *name);\n\n/**\n * # # nk_window_get_bounds\n * \\returns a rectangle with screen position and size of the currently processed window\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * struct nk_rect nk_window_get_bounds(const struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns a `nk_rect` struct with window upper left window position and size\n\n */\nNK_API struct nk_rect nk_window_get_bounds(const struct nk_context *ctx);\n\n/**\n * # # nk_window_get_position\n * \\returns the position of the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * struct nk_vec2 nk_window_get_position(const struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns a `nk_vec2` struct with window upper left position\n\n */\nNK_API struct nk_vec2 nk_window_get_position(const struct nk_context *ctx);\n\n/**\n * # # nk_window_get_size\n * \\returns the size with width and height of the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * struct nk_vec2 nk_window_get_size(const struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns a `nk_vec2` struct with window width and height\n\n */\nNK_API struct nk_vec2 nk_window_get_size(const struct nk_context *ctx);\n\n/**\n * nk_window_get_width\n * \\returns the width of the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * float nk_window_get_width(const struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns the current window width\n */\nNK_API float nk_window_get_width(const struct nk_context *ctx);\n\n/**\n * # # nk_window_get_height\n * \\returns the height of the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * float nk_window_get_height(const struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns the current window height\n\n */\nNK_API float nk_window_get_height(const struct nk_context* ctx);\n\n/**\n * # # nk_window_get_panel\n * \\returns the underlying panel which contains all processing state of the current window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * !!! \\warning\n *     Do not keep the returned panel pointer around, it is only valid until `nk_end`\n * ```c\n * struct nk_panel* nk_window_get_panel(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns a pointer to window internal `nk_panel` state.\n\n */\nNK_API struct nk_panel* nk_window_get_panel(const struct nk_context* ctx);\n\n/**\n * # # nk_window_get_content_region\n * \\returns the position and size of the currently visible and non-clipped space\n * inside the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n *\n * ```c\n * struct nk_rect nk_window_get_content_region(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `nk_rect` struct with screen position and size (no scrollbar offset)\n * of the visible space inside the current window\n\n */\nNK_API struct nk_rect nk_window_get_content_region(const struct nk_context* ctx);\n\n/**\n * # # nk_window_get_content_region_min\n * \\returns the upper left position of the currently visible and non-clipped\n * space inside the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n *\n * ```c\n * struct nk_vec2 nk_window_get_content_region_min(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * returns `nk_vec2` struct with  upper left screen position (no scrollbar offset)\n * of the visible space inside the current window\n\n */\nNK_API struct nk_vec2 nk_window_get_content_region_min(const struct nk_context *ctx);\n\n/**\n * # # nk_window_get_content_region_max\n * \\returns the lower right screen position of the currently visible and\n * non-clipped space inside the currently processed window.\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n *\n * ```c\n * struct nk_vec2 nk_window_get_content_region_max(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `nk_vec2` struct with lower right screen position (no scrollbar offset)\n * of the visible space inside the current window\n\n */\nNK_API struct nk_vec2 nk_window_get_content_region_max(const struct nk_context *ctx);\n\n/**\n * # # nk_window_get_content_region_size\n * \\returns the size of the currently visible and non-clipped space inside the\n * currently processed window\n *\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n *\n * ```c\n * struct nk_vec2 nk_window_get_content_region_size(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `nk_vec2` struct with size the visible space inside the current window\n\n */\nNK_API struct nk_vec2 nk_window_get_content_region_size(const struct nk_context *ctx);\n\n/**\n * # # nk_window_get_canvas\n * \\returns the draw command buffer. Can be used to draw custom widgets\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * !!! \\warning\n *     Do not keep the returned command buffer pointer around it is only valid until `nk_end`\n *\n * ```c\n * struct nk_command_buffer* nk_window_get_canvas(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns a pointer to window internal `nk_command_buffer` struct used as\n * drawing canvas. Can be used to do custom drawing.\n */\nNK_API struct nk_command_buffer* nk_window_get_canvas(const struct nk_context* ctx);\n\n/**\n * # # nk_window_get_scroll\n * Gets the scroll offset for the current window\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n *\n * ```c\n * void nk_window_get_scroll(struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y);\n * ```\n *\n * Parameter    | Description\n * -------------|-----------------------------------------------------------\n * \\param[in] ctx      | Must point to an previously initialized `nk_context` struct\n * \\param[in] offset_x | A pointer to the x offset output (or NULL to ignore)\n * \\param[in] offset_y | A pointer to the y offset output (or NULL to ignore)\n\n */\nNK_API void nk_window_get_scroll(const struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y);\n\n/**\n * # # nk_window_has_focus\n * \\returns if the currently processed window is currently active\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * nk_bool nk_window_has_focus(const struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `false(0)` if current window is not active or `true(1)` if it is\n\n */\nNK_API nk_bool nk_window_has_focus(const struct nk_context *ctx);\n\n/**\n * # # nk_window_is_hovered\n * Return if the current window is being hovered\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n * ```c\n * nk_bool nk_window_is_hovered(struct nk_context *ctx);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `true(1)` if current window is hovered or `false(0)` otherwise\n\n */\nNK_API nk_bool nk_window_is_hovered(const struct nk_context *ctx);\n\n/**\n * # # nk_window_is_collapsed\n * \\returns if the window with given name is currently minimized/collapsed\n * ```c\n * nk_bool nk_window_is_collapsed(struct nk_context *ctx, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of window you want to check if it is collapsed\n *\n * \\returns `true(1)` if current window is minimized and `false(0)` if window not\n * found or is not minimized\n\n */\nNK_API nk_bool nk_window_is_collapsed(const struct nk_context *ctx, const char *name);\n\n/**\n * # # nk_window_is_closed\n * \\returns if the window with given name was closed by calling `nk_close`\n * ```c\n * nk_bool nk_window_is_closed(struct nk_context *ctx, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of window you want to check if it is closed\n *\n * \\returns `true(1)` if current window was closed or `false(0)` window not found or not closed\n\n */\nNK_API nk_bool nk_window_is_closed(const struct nk_context *ctx, const char* name);\n\n/**\n * # # nk_window_is_hidden\n * \\returns if the window with given name is hidden\n * ```c\n * nk_bool nk_window_is_hidden(struct nk_context *ctx, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of window you want to check if it is hidden\n *\n * \\returns `true(1)` if current window is hidden or `false(0)` window not found or visible\n\n */\nNK_API nk_bool nk_window_is_hidden(const struct nk_context *ctx, const char* name);\n\n/**\n * # # nk_window_is_active\n * Same as nk_window_has_focus for some reason\n * ```c\n * nk_bool nk_window_is_active(struct nk_context *ctx, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of window you want to check if it is active\n *\n * \\returns `true(1)` if current window is active or `false(0)` window not found or not active\n */\nNK_API nk_bool nk_window_is_active(const struct nk_context *ctx, const char* name);\n\n/**\n * # # nk_window_is_any_hovered\n * \\returns if the any window is being hovered\n * ```c\n * nk_bool nk_window_is_any_hovered(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `true(1)` if any window is hovered or `false(0)` otherwise\n */\nNK_API nk_bool nk_window_is_any_hovered(const struct nk_context *ctx);\n\n/**\n * # # nk_item_is_any_active\n * \\returns if the any window is being hovered or any widget is currently active.\n * Can be used to decide if input should be processed by UI or your specific input handling.\n * Example could be UI and 3D camera to move inside a 3D space.\n * ```c\n * nk_bool nk_item_is_any_active(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n *\n * \\returns `true(1)` if any window is hovered or any item is active or `false(0)` otherwise\n\n */\nNK_API nk_bool nk_item_is_any_active(const struct nk_context *ctx);\n\n/**\n * # # nk_window_set_bounds\n * Updates position and size of window with passed in name\n * ```c\n * void nk_window_set_bounds(struct nk_context*, const char *name, struct nk_rect bounds);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to modify both position and size\n * \\param[in] bounds  | Must point to a `nk_rect` struct with the new position and size\n\n */\nNK_API void nk_window_set_bounds(struct nk_context *ctx, const char *name, struct nk_rect bounds);\n\n/**\n * # # nk_window_set_position\n * Updates position of window with passed name\n * ```c\n * void nk_window_set_position(struct nk_context*, const char *name, struct nk_vec2 pos);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to modify both position\n * \\param[in] pos     | Must point to a `nk_vec2` struct with the new position\n\n */\nNK_API void nk_window_set_position(struct nk_context *ctx, const char *name, struct nk_vec2 pos);\n\n/**\n * # # nk_window_set_size\n * Updates size of window with passed in name\n * ```c\n * void nk_window_set_size(struct nk_context*, const char *name, struct nk_vec2);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to modify both window size\n * \\param[in] size    | Must point to a `nk_vec2` struct with new window size\n\n */\nNK_API void nk_window_set_size(struct nk_context *ctx, const char *name, struct nk_vec2 size);\n\n/**\n * # # nk_window_set_focus\n * Sets the window with given name as active\n * ```c\n * void nk_window_set_focus(struct nk_context*, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to set focus on\n\n */\nNK_API void nk_window_set_focus(struct nk_context *ctx, const char *name);\n\n/**\n * # # nk_window_set_scroll\n * Sets the scroll offset for the current window\n * !!! \\warning\n *     Only call this function between calls `nk_begin_xxx` and `nk_end`\n *\n * ```c\n * void nk_window_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y);\n * ```\n *\n * Parameter    | Description\n * -------------|-----------------------------------------------------------\n * \\param[in] ctx      | Must point to an previously initialized `nk_context` struct\n * \\param[in] offset_x | The x offset to scroll to\n * \\param[in] offset_y | The y offset to scroll to\n\n */\nNK_API void nk_window_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y);\n\n/**\n * # # nk_window_close\n * Closes a window and marks it for being freed at the end of the frame\n * ```c\n * void nk_window_close(struct nk_context *ctx, const char *name);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to close\n\n */\nNK_API void nk_window_close(struct nk_context *ctx, const char *name);\n\n/**\n * # # nk_window_collapse\n * Updates collapse state of a window with given name\n * ```c\n * void nk_window_collapse(struct nk_context*, const char *name, enum nk_collapse_states state);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to close\n * \\param[in] state   | value out of nk_collapse_states section\n\n */\nNK_API void nk_window_collapse(struct nk_context *ctx, const char *name, enum nk_collapse_states state);\n\n/**\n * # # nk_window_collapse_if\n * Updates collapse state of a window with given name if given condition is met\n * ```c\n * void nk_window_collapse_if(struct nk_context*, const char *name, enum nk_collapse_states, int cond);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to either collapse or maximize\n * \\param[in] state   | value out of nk_collapse_states section the window should be put into\n * \\param[in] cond    | condition that has to be met to actually commit the collapse state change\n\n */\nNK_API void nk_window_collapse_if(struct nk_context *ctx, const char *name, enum nk_collapse_states state, int cond);\n\n/**\n * # # nk_window_show\n * updates visibility state of a window with given name\n * ```c\n * void nk_window_show(struct nk_context*, const char *name, enum nk_show_states);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to either collapse or maximize\n * \\param[in] state   | state with either visible or hidden to modify the window with\n */\nNK_API void nk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states state);\n\n/**\n * # # nk_window_show_if\n * Updates visibility state of a window with given name if a given condition is met\n * ```c\n * void nk_window_show_if(struct nk_context*, const char *name, enum nk_show_states, int cond);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] name    | Identifier of the window to either hide or show\n * \\param[in] state   | state with either visible or hidden to modify the window with\n * \\param[in] cond    | condition that has to be met to actually commit the visibility state change\n\n */\nNK_API void nk_window_show_if(struct nk_context *ctx, const char *name, enum nk_show_states state, int cond);\n\n/**\n * # # nk_window_show_if\n * Line for visual separation. Draws a line with thickness determined by the current row height.\n * ```c\n * void nk_rule_horizontal(struct nk_context *ctx, struct nk_color color, nk_bool rounding)\n * ```\n *\n * Parameter       | Description\n * ----------------|-------------------------------------------------------\n * \\param[in] ctx         | Must point to an previously initialized `nk_context` struct\n * \\param[in] color       | Color of the horizontal line\n * \\param[in] rounding    | Whether or not to make the line round\n */\nNK_API void nk_rule_horizontal(struct nk_context *ctx, struct nk_color color, nk_bool rounding);\n\n/* =============================================================================\n *\n *                                  LAYOUT\n *\n * =============================================================================*/\n/**\n * \\page Layouting\n * Layouting in general describes placing widget inside a window with position and size.\n * While in this particular implementation there are five different APIs for layouting\n * each with different trade offs between control and ease of use. <br /><br />\n *\n * All layouting methods in this library are based around the concept of a row.\n * A row has a height the window content grows by and a number of columns and each\n * layouting method specifies how each widget is placed inside the row.\n * After a row has been allocated by calling a layouting functions and then\n * filled with widgets will advance an internal pointer over the allocated row. <br /><br />\n *\n * To actually define a layout you just call the appropriate layouting function\n * and each subsequent widget call will place the widget as specified. Important\n * here is that if you define more widgets then columns defined inside the layout\n * functions it will allocate the next row without you having to make another layouting call. <br /><br />\n *\n * Biggest limitation with using all these APIs outside the `nk_layout_space_xxx` API\n * is that you have to define the row height for each. However the row height\n * often depends on the height of the font. <br /><br />\n *\n * To fix that internally nuklear uses a minimum row height that is set to the\n * height plus padding of currently active font and overwrites the row height\n * value if zero. <br /><br />\n *\n * If you manually want to change the minimum row height then\n * use nk_layout_set_min_row_height, and use nk_layout_reset_min_row_height to\n * reset it back to be derived from font height. <br /><br />\n *\n * Also if you change the font in nuklear it will automatically change the minimum\n * row height for you and. This means if you change the font but still want\n * a minimum row height smaller than the font you have to repush your value. <br /><br />\n *\n * For actually more advanced UI I would even recommend using the `nk_layout_space_xxx`\n * layouting method in combination with a cassowary constraint solver (there are\n * some versions on github with permissive license model) to take over all control over widget\n * layouting yourself. However for quick and dirty layouting using all the other layouting\n * functions should be fine.\n *\n * # Usage\n * 1. __nk_layout_row_dynamic__<br /><br />\n *    The easiest layouting function is `nk_layout_row_dynamic`. It provides each\n *    widgets with same horizontal space inside the row and dynamically grows\n *    if the owning window grows in width. So the number of columns dictates\n *    the size of each widget dynamically by formula:\n *\n *    ```c\n *    widget_width = (window_width - padding - spacing) * (1/column_count)\n *    ```\n *\n *    Just like all other layouting APIs if you define more widget than columns this\n *    library will allocate a new row and keep all layouting parameters previously\n *    defined.\n *\n *    ```c\n *    if (nk_begin_xxx(...) {\n *        // first row with height: 30 composed of two widgets\n *        nk_layout_row_dynamic(&ctx, 30, 2);\n *        nk_widget(...);\n *        nk_widget(...);\n *        //\n *        // second row with same parameter as defined above\n *        nk_widget(...);\n *        nk_widget(...);\n *        //\n *        // third row uses 0 for height which will use auto layouting\n *        nk_layout_row_dynamic(&ctx, 0, 2);\n *        nk_widget(...);\n *        nk_widget(...);\n *    }\n *    nk_end(...);\n *    ```\n *\n * 2. __nk_layout_row_static__<br /><br />\n *    Another easy layouting function is `nk_layout_row_static`. It provides each\n *    widget with same horizontal pixel width inside the row and does not grow\n *    if the owning window scales smaller or bigger.\n *\n *    ```c\n *    if (nk_begin_xxx(...) {\n *        // first row with height: 30 composed of two widgets with width: 80\n *        nk_layout_row_static(&ctx, 30, 80, 2);\n *        nk_widget(...);\n *        nk_widget(...);\n *        //\n *        // second row with same parameter as defined above\n *        nk_widget(...);\n *        nk_widget(...);\n *        //\n *        // third row uses 0 for height which will use auto layouting\n *        nk_layout_row_static(&ctx, 0, 80, 2);\n *        nk_widget(...);\n *        nk_widget(...);\n *    }\n *    nk_end(...);\n *    ```\n *\n * 3. __nk_layout_row_xxx__<br /><br />\n *    A little bit more advanced layouting API are functions `nk_layout_row_begin`,\n *    `nk_layout_row_push` and `nk_layout_row_end`. They allow to directly\n *    specify each column pixel or window ratio in a row. It supports either\n *    directly setting per column pixel width or widget window ratio but not\n *    both. Furthermore it is a immediate mode API so each value is directly\n *    pushed before calling a widget. Therefore the layout is not automatically\n *    repeating like the last two layouting functions.\n *\n *    ```c\n *    if (nk_begin_xxx(...) {\n *        // first row with height: 25 composed of two widgets with width 60 and 40\n *        nk_layout_row_begin(ctx, NK_STATIC, 25, 2);\n *        nk_layout_row_push(ctx, 60);\n *        nk_widget(...);\n *        nk_layout_row_push(ctx, 40);\n *        nk_widget(...);\n *        nk_layout_row_end(ctx);\n *        //\n *        // second row with height: 25 composed of two widgets with window ratio 0.25 and 0.75\n *        nk_layout_row_begin(ctx, NK_DYNAMIC, 25, 2);\n *        nk_layout_row_push(ctx, 0.25f);\n *        nk_widget(...);\n *        nk_layout_row_push(ctx, 0.75f);\n *        nk_widget(...);\n *        nk_layout_row_end(ctx);\n *        //\n *        // third row with auto generated height: composed of two widgets with window ratio 0.25 and 0.75\n *        nk_layout_row_begin(ctx, NK_DYNAMIC, 0, 2);\n *        nk_layout_row_push(ctx, 0.25f);\n *        nk_widget(...);\n *        nk_layout_row_push(ctx, 0.75f);\n *        nk_widget(...);\n *        nk_layout_row_end(ctx);\n *    }\n *    nk_end(...);\n *    ```\n *\n * 4. __nk_layout_row__<br /><br />\n *    The array counterpart to API nk_layout_row_xxx is the single nk_layout_row\n *    functions. Instead of pushing either pixel or window ratio for every widget\n *    it allows to define it by array. The trade of for less control is that\n *    `nk_layout_row` is automatically repeating. Otherwise the behavior is the\n *    same.\n *\n *    ```c\n *    if (nk_begin_xxx(...) {\n *        // two rows with height: 30 composed of two widgets with width 60 and 40\n *        const float ratio[] = {60,40};\n *        nk_layout_row(ctx, NK_STATIC, 30, 2, ratio);\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *        //\n *        // two rows with height: 30 composed of two widgets with window ratio 0.25 and 0.75\n *        const float ratio[] = {0.25, 0.75};\n *        nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio);\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *        //\n *        // two rows with auto generated height composed of two widgets with window ratio 0.25 and 0.75\n *        const float ratio[] = {0.25, 0.75};\n *        nk_layout_row(ctx, NK_DYNAMIC, 30, 2, ratio);\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *    }\n *    nk_end(...);\n *    ```\n *\n * 5. __nk_layout_row_template_xxx__<br /><br />\n *    The most complex and second most flexible API is a simplified flexbox version without\n *    line wrapping and weights for dynamic widgets. It is an immediate mode API but\n *    unlike `nk_layout_row_xxx` it has auto repeat behavior and needs to be called\n *    before calling the templated widgets.\n *    The row template layout has three different per widget size specifier. The first\n *    one is the `nk_layout_row_template_push_static`  with fixed widget pixel width.\n *    They do not grow if the row grows and will always stay the same.\n *    The second size specifier is `nk_layout_row_template_push_variable`\n *    which defines a minimum widget size but it also can grow if more space is available\n *    not taken by other widgets.\n *    Finally there are dynamic widgets with `nk_layout_row_template_push_dynamic`\n *    which are completely flexible and unlike variable widgets can even shrink\n *    to zero if not enough space is provided.\n *\n *    ```c\n *    if (nk_begin_xxx(...) {\n *        // two rows with height: 30 composed of three widgets\n *        nk_layout_row_template_begin(ctx, 30);\n *        nk_layout_row_template_push_dynamic(ctx);\n *        nk_layout_row_template_push_variable(ctx, 80);\n *        nk_layout_row_template_push_static(ctx, 80);\n *        nk_layout_row_template_end(ctx);\n *        //\n *        // first row\n *        nk_widget(...); // dynamic widget can go to zero if not enough space\n *        nk_widget(...); // variable widget with min 80 pixel but can grow bigger if enough space\n *        nk_widget(...); // static widget with fixed 80 pixel width\n *        //\n *        // second row same layout\n *        nk_widget(...);\n *        nk_widget(...);\n *        nk_widget(...);\n *    }\n *    nk_end(...);\n *    ```\n *\n * 6. __nk_layout_space_xxx__<br /><br />\n *    Finally the most flexible API directly allows you to place widgets inside the\n *    window. The space layout API is an immediate mode API which does not support\n *    row auto repeat and directly sets position and size of a widget. Position\n *    and size hereby can be either specified as ratio of allocated space or\n *    allocated space local position and pixel size. Since this API is quite\n *    powerful there are a number of utility functions to get the available space\n *    and convert between local allocated space and screen space.\n *\n *    ```c\n *    if (nk_begin_xxx(...) {\n *        // static row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered)\n *        nk_layout_space_begin(ctx, NK_STATIC, 500, INT_MAX);\n *        nk_layout_space_push(ctx, nk_rect(0,0,150,200));\n *        nk_widget(...);\n *        nk_layout_space_push(ctx, nk_rect(200,200,100,200));\n *        nk_widget(...);\n *        nk_layout_space_end(ctx);\n *        //\n *        // dynamic row with height: 500 (you can set column count to INT_MAX if you don't want to be bothered)\n *        nk_layout_space_begin(ctx, NK_DYNAMIC, 500, INT_MAX);\n *        nk_layout_space_push(ctx, nk_rect(0.5,0.5,0.1,0.1));\n *        nk_widget(...);\n *        nk_layout_space_push(ctx, nk_rect(0.7,0.6,0.1,0.1));\n *        nk_widget(...);\n *    }\n *    nk_end(...);\n *    ```\n *\n * # Reference\n * Function                                     | Description\n * ---------------------------------------------|------------------------------------\n * \\ref nk_layout_set_min_row_height            | Set the currently used minimum row height to a specified value\n * \\ref nk_layout_reset_min_row_height          | Resets the currently used minimum row height to font height\n * \\ref nk_layout_widget_bounds                 | Calculates current width a static layout row can fit inside a window\n * \\ref nk_layout_ratio_from_pixel              | Utility functions to calculate window ratio from pixel size\n * \\ref nk_layout_row_dynamic                   | Current layout is divided into n same sized growing columns\n * \\ref nk_layout_row_static                    | Current layout is divided into n same fixed sized columns\n * \\ref nk_layout_row_begin                     | Starts a new row with given height and number of columns\n * \\ref nk_layout_row_push                      | Pushes another column with given size or window ratio\n * \\ref nk_layout_row_end                       | Finished previously started row\n * \\ref nk_layout_row                           | Specifies row columns in array as either window ratio or size\n * \\ref nk_layout_row_template_begin            | Begins the row template declaration\n * \\ref nk_layout_row_template_push_dynamic     | Adds a dynamic column that dynamically grows and can go to zero if not enough space\n * \\ref nk_layout_row_template_push_variable    | Adds a variable column that dynamically grows but does not shrink below specified pixel width\n * \\ref nk_layout_row_template_push_static      | Adds a static column that does not grow and will always have the same size\n * \\ref nk_layout_row_template_end              | Marks the end of the row template\n * \\ref nk_layout_space_begin                   | Begins a new layouting space that allows to specify each widgets position and size\n * \\ref nk_layout_space_push                    | Pushes position and size of the next widget in own coordinate space either as pixel or ratio\n * \\ref nk_layout_space_end                     | Marks the end of the layouting space\n * \\ref nk_layout_space_bounds                  | Callable after nk_layout_space_begin and returns total space allocated\n * \\ref nk_layout_space_to_screen               | Converts vector from nk_layout_space coordinate space into screen space\n * \\ref nk_layout_space_to_local                | Converts vector from screen space into nk_layout_space coordinates\n * \\ref nk_layout_space_rect_to_screen          | Converts rectangle from nk_layout_space coordinate space into screen space\n * \\ref nk_layout_space_rect_to_local           | Converts rectangle from screen space into nk_layout_space coordinates\n */\n\n\n\nenum nk_widget_align {\n    NK_WIDGET_ALIGN_LEFT        = 0x01,\n    NK_WIDGET_ALIGN_CENTERED    = 0x02,\n    NK_WIDGET_ALIGN_RIGHT       = 0x04,\n    NK_WIDGET_ALIGN_TOP         = 0x08,\n    NK_WIDGET_ALIGN_MIDDLE      = 0x10,\n    NK_WIDGET_ALIGN_BOTTOM      = 0x20\n};\nenum nk_widget_alignment {\n    NK_WIDGET_LEFT        = NK_WIDGET_ALIGN_MIDDLE|NK_WIDGET_ALIGN_LEFT,\n    NK_WIDGET_CENTERED    = NK_WIDGET_ALIGN_MIDDLE|NK_WIDGET_ALIGN_CENTERED,\n    NK_WIDGET_RIGHT       = NK_WIDGET_ALIGN_MIDDLE|NK_WIDGET_ALIGN_RIGHT\n};\n\n/**\n * Sets the currently used minimum row height.\n * !!! \\warning\n *     The passed height needs to include both your preferred row height\n *     as well as padding. No internal padding is added.\n *\n * ```c\n * void nk_layout_set_min_row_height(struct nk_context*, float height);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] height  | New minimum row height to be used for auto generating the row height\n */\nNK_API void nk_layout_set_min_row_height(struct nk_context*, float height);\n\n/**\n * Reset the currently used minimum row height back to `font_height + text_padding + padding`\n * ```c\n * void nk_layout_reset_min_row_height(struct nk_context*);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n */\nNK_API void nk_layout_reset_min_row_height(struct nk_context*);\n\n/**\n * \\brief Returns the width of the next row allocate by one of the layouting functions\n *\n * \\details\n * ```c\n * struct nk_rect nk_layout_widget_bounds(struct nk_context*);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n *\n * \\return `nk_rect` with both position and size of the next row\n */\nNK_API struct nk_rect nk_layout_widget_bounds(const struct nk_context *ctx);\n\n/**\n * \\brief Utility functions to calculate window ratio from pixel size\n *\n * \\details\n * ```c\n * float nk_layout_ratio_from_pixel(struct nk_context*, float pixel_width);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] pixel   | Pixel_width to convert to window ratio\n *\n * \\returns `nk_rect` with both position and size of the next row\n */\nNK_API float nk_layout_ratio_from_pixel(const struct nk_context *ctx, float pixel_width);\n\n/**\n * \\brief Sets current row layout to share horizontal space\n * between @cols number of widgets evenly. Once called all subsequent widget\n * calls greater than @cols will allocate a new row with same layout.\n *\n * \\details\n * ```c\n * void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] height  | Holds height of each widget in row or zero for auto layouting\n * \\param[in] columns | Number of widget inside row\n */\nNK_API void nk_layout_row_dynamic(struct nk_context *ctx, float height, int cols);\n\n/**\n * \\brief Sets current row layout to fill @cols number of widgets\n * in row with same @item_width horizontal size. Once called all subsequent widget\n * calls greater than @cols will allocate a new row with same layout.\n *\n * \\details\n * ```c\n * void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] height  | Holds height of each widget in row or zero for auto layouting\n * \\param[in] width   | Holds pixel width of each widget in the row\n * \\param[in] columns | Number of widget inside row\n */\nNK_API void nk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols);\n\n/**\n * \\brief Starts a new dynamic or fixed row with given height and columns.\n *\n * \\details\n * ```c\n * void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] fmt     | either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns\n * \\param[in] height  | holds height of each widget in row or zero for auto layouting\n * \\param[in] columns | Number of widget inside row\n */\nNK_API void nk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt, float row_height, int cols);\n\n/**\n * \\breif Specifies either window ratio or width of a single column\n *\n * \\details\n * ```c\n * void nk_layout_row_push(struct nk_context*, float value);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] value   | either a window ratio or fixed width depending on @fmt in previous `nk_layout_row_begin` call\n */\nNK_API void nk_layout_row_push(struct nk_context*, float value);\n\n/**\n * \\brief Finished previously started row\n *\n * \\details\n * ```c\n * void nk_layout_row_end(struct nk_context*);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n */\nNK_API void nk_layout_row_end(struct nk_context*);\n\n/**\n * \\brief Specifies row columns in array as either window ratio or size\n *\n * \\details\n * ```c\n * void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] fmt     | Either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns\n * \\param[in] height  | Holds height of each widget in row or zero for auto layouting\n * \\param[in] columns | Number of widget inside row\n */\nNK_API void nk_layout_row(struct nk_context*, enum nk_layout_format, float height, int cols, const float *ratio);\n\n/**\n * # # nk_layout_row_template_begin\n * Begins the row template declaration\n * ```c\n * void nk_layout_row_template_begin(struct nk_context*, float row_height);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] height  | Holds height of each widget in row or zero for auto layouting\n */\nNK_API void nk_layout_row_template_begin(struct nk_context*, float row_height);\n\n/**\n * # # nk_layout_row_template_push_dynamic\n * Adds a dynamic column that dynamically grows and can go to zero if not enough space\n * ```c\n * void nk_layout_row_template_push_dynamic(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] height  | Holds height of each widget in row or zero for auto layouting\n */\nNK_API void nk_layout_row_template_push_dynamic(struct nk_context*);\n\n/**\n * # # nk_layout_row_template_push_variable\n * Adds a variable column that dynamically grows but does not shrink below specified pixel width\n * ```c\n * void nk_layout_row_template_push_variable(struct nk_context*, float min_width);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] width   | Holds the minimum pixel width the next column must always be\n */\nNK_API void nk_layout_row_template_push_variable(struct nk_context*, float min_width);\n\n/**\n * # # nk_layout_row_template_push_static\n * Adds a static column that does not grow and will always have the same size\n * ```c\n * void nk_layout_row_template_push_static(struct nk_context*, float width);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] width   | Holds the absolute pixel width value the next column must be\n */\nNK_API void nk_layout_row_template_push_static(struct nk_context*, float width);\n\n/**\n * # # nk_layout_row_template_end\n * Marks the end of the row template\n * ```c\n * void nk_layout_row_template_end(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n */\nNK_API void nk_layout_row_template_end(struct nk_context*);\n\n/**\n * # # nk_layout_space_begin\n * Begins a new layouting space that allows to specify each widgets position and size.\n * ```c\n * void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_begin_xxx`\n * \\param[in] fmt     | Either `NK_DYNAMIC` for window ratio or `NK_STATIC` for fixed size columns\n * \\param[in] height  | Holds height of each widget in row or zero for auto layouting\n * \\param[in] columns | Number of widgets inside row\n */\nNK_API void nk_layout_space_begin(struct nk_context*, enum nk_layout_format, float height, int widget_count);\n\n/**\n * # # nk_layout_space_push\n * Pushes position and size of the next widget in own coordinate space either as pixel or ratio\n * ```c\n * void nk_layout_space_push(struct nk_context *ctx, struct nk_rect bounds);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n * \\param[in] bounds  | Position and size in laoyut space local coordinates\n */\nNK_API void nk_layout_space_push(struct nk_context*, struct nk_rect bounds);\n\n/**\n * # # nk_layout_space_end\n * Marks the end of the layout space\n * ```c\n * void nk_layout_space_end(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n */\nNK_API void nk_layout_space_end(struct nk_context*);\n\n/**\n * # # nk_layout_space_bounds\n * Utility function to calculate total space allocated for `nk_layout_space`\n * ```c\n * struct nk_rect nk_layout_space_bounds(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n *\n * \\returns `nk_rect` holding the total space allocated\n */\nNK_API struct nk_rect nk_layout_space_bounds(const struct nk_context *ctx);\n\n/**\n * # # nk_layout_space_to_screen\n * Converts vector from nk_layout_space coordinate space into screen space\n * ```c\n * struct nk_vec2 nk_layout_space_to_screen(struct nk_context*, struct nk_vec2);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n * \\param[in] vec     | Position to convert from layout space into screen coordinate space\n *\n * \\returns transformed `nk_vec2` in screen space coordinates\n */\nNK_API struct nk_vec2 nk_layout_space_to_screen(const struct nk_context* ctx, struct nk_vec2 vec);\n\n/**\n * # # nk_layout_space_to_local\n * Converts vector from layout space into screen space\n * ```c\n * struct nk_vec2 nk_layout_space_to_local(struct nk_context*, struct nk_vec2);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n * \\param[in] vec     | Position to convert from screen space into layout coordinate space\n *\n * \\returns transformed `nk_vec2` in layout space coordinates\n */\nNK_API struct nk_vec2 nk_layout_space_to_local(const struct nk_context *ctx, struct nk_vec2 vec);\n\n/**\n * # # nk_layout_space_rect_to_screen\n * Converts rectangle from screen space into layout space\n * ```c\n * struct nk_rect nk_layout_space_rect_to_screen(struct nk_context*, struct nk_rect);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n * \\param[in] bounds  | Rectangle to convert from layout space into screen space\n *\n * \\returns transformed `nk_rect` in screen space coordinates\n */\nNK_API struct nk_rect nk_layout_space_rect_to_screen(const struct nk_context *ctx, struct nk_rect bounds);\n\n/**\n * # # nk_layout_space_rect_to_local\n * Converts rectangle from layout space into screen space\n * ```c\n * struct nk_rect nk_layout_space_rect_to_local(struct nk_context*, struct nk_rect);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n * \\param[in] bounds  | Rectangle to convert from layout space into screen space\n *\n * \\returns transformed `nk_rect` in layout space coordinates\n */\nNK_API struct nk_rect nk_layout_space_rect_to_local(const struct nk_context *ctx, struct nk_rect bounds);\n\n/**\n * # # nk_spacer\n * Spacer is a dummy widget that consumes space as usual but doesn't draw anything\n * ```c\n * void nk_spacer(struct nk_context* );\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after call `nk_layout_space_begin`\n *\n */\nNK_API void nk_spacer(struct nk_context *ctx);\n\n\n/* =============================================================================\n *\n *                                  GROUP\n *\n * =============================================================================*/\n/**\n * \\page Groups\n * Groups are basically windows inside windows. They allow to subdivide space\n * in a window to layout widgets as a group. Almost all more complex widget\n * layouting requirements can be solved using groups and basic layouting\n * fuctionality. Groups just like windows are identified by an unique name and\n * internally keep track of scrollbar offsets by default. However additional\n * versions are provided to directly manage the scrollbar.\n *\n * # Usage\n * To create a group you have to call one of the three `nk_group_begin_xxx`\n * functions to start group declarations and `nk_group_end` at the end. Furthermore it\n * is required to check the return value of `nk_group_begin_xxx` and only process\n * widgets inside the window if the value is not 0.\n * Nesting groups is possible and even encouraged since many layouting schemes\n * can only be achieved by nesting. Groups, unlike windows, need `nk_group_end`\n * to be only called if the corresponding `nk_group_begin_xxx` call does not return 0:\n *\n * ```c\n * if (nk_group_begin_xxx(ctx, ...) {\n *     // [... widgets ...]\n *     nk_group_end(ctx);\n * }\n * ```\n *\n * In the grand concept groups can be called after starting a window\n * with `nk_begin_xxx` and before calling `nk_end`:\n *\n * ```c\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     // Input\n *     Event evt;\n *     nk_input_begin(&ctx);\n *     while (GetEvent(&evt)) {\n *         if (evt.type == MOUSE_MOVE)\n *             nk_input_motion(&ctx, evt.motion.x, evt.motion.y);\n *         else if (evt.type == [...]) {\n *             nk_input_xxx(...);\n *         }\n *     }\n *     nk_input_end(&ctx);\n *     //\n *     // Window\n *     if (nk_begin_xxx(...) {\n *         // [...widgets...]\n *         nk_layout_row_dynamic(...);\n *         if (nk_group_begin_xxx(ctx, ...) {\n *             //[... widgets ...]\n *             nk_group_end(ctx);\n *         }\n *     }\n *     nk_end(ctx);\n *     //\n *     // Draw\n *     const struct nk_command *cmd = 0;\n *     nk_foreach(cmd, &ctx) {\n *     switch (cmd->type) {\n *     case NK_COMMAND_LINE:\n *         your_draw_line_function(...)\n *         break;\n *     case NK_COMMAND_RECT\n *         your_draw_rect_function(...)\n *         break;\n *     case ...:\n *         // [...]\n *     }\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n * # Reference\n * Function                        | Description\n * --------------------------------|-------------------------------------------\n * \\ref nk_group_begin                  | Start a new group with internal scrollbar handling\n * \\ref nk_group_begin_titled           | Start a new group with separated name and title and internal scrollbar handling\n * \\ref nk_group_end                    | Ends a group. Should only be called if nk_group_begin returned non-zero\n * \\ref nk_group_scrolled_offset_begin  | Start a new group with manual separated handling of scrollbar x- and y-offset\n * \\ref nk_group_scrolled_begin         | Start a new group with manual scrollbar handling\n * \\ref nk_group_scrolled_end           | Ends a group with manual scrollbar handling. Should only be called if nk_group_begin returned non-zero\n * \\ref nk_group_get_scroll             | Gets the scroll offset for the given group\n * \\ref nk_group_set_scroll             | Sets the scroll offset for the given group\n */\n\n /**\n * \\brief Starts a new widget group. Requires a previous layouting function to specify a pos/size.\n * ```c\n * nk_bool nk_group_begin(struct nk_context*, const char *title, nk_flags);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] title   | Must be an unique identifier for this group that is also used for the group header\n * \\param[in] flags   | Window flags defined in the nk_panel_flags section with a number of different group behaviors\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_group_begin(struct nk_context*, const char *title, nk_flags);\n\n /**\n * \\brief Starts a new widget group. Requires a previous layouting function to specify a pos/size.\n * ```c\n * nk_bool nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags);\n * ```\n *\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] id      | Must be an unique identifier for this group\n * \\param[in] title   | Group header title\n * \\param[in] flags   | Window flags defined in the nk_panel_flags section with a number of different group behaviors\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_group_begin_titled(struct nk_context*, const char *name, const char *title, nk_flags);\n\n/**\n * # # nk_group_end\n * Ends a widget group\n * ```c\n * void nk_group_end(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n */\nNK_API void nk_group_end(struct nk_context*);\n\n/**\n * # # nk_group_scrolled_offset_begin\n * starts a new widget group. requires a previous layouting function to specify\n * a size. Does not keep track of scrollbar.\n * ```c\n * nk_bool nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] x_offset| Scrollbar x-offset to offset all widgets inside the group horizontally.\n * \\param[in] y_offset| Scrollbar y-offset to offset all widgets inside the group vertically\n * \\param[in] title   | Window unique group title used to both identify and display in the group header\n * \\param[in] flags   | Window flags from the nk_panel_flags section\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_group_scrolled_offset_begin(struct nk_context*, nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags);\n\n/**\n * # # nk_group_scrolled_begin\n * Starts a new widget group. requires a previous\n * layouting function to specify a size. Does not keep track of scrollbar.\n * ```c\n * nk_bool nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] off     | Both x- and y- scroll offset. Allows for manual scrollbar control\n * \\param[in] title   | Window unique group title used to both identify and display in the group header\n * \\param[in] flags   | Window flags from nk_panel_flags section\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_group_scrolled_begin(struct nk_context*, struct nk_scroll *off, const char *title, nk_flags);\n\n/**\n * # # nk_group_scrolled_end\n * Ends a widget group after calling nk_group_scrolled_offset_begin or nk_group_scrolled_begin.\n * ```c\n * void nk_group_scrolled_end(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n */\nNK_API void nk_group_scrolled_end(struct nk_context*);\n\n/**\n * # # nk_group_get_scroll\n * Gets the scroll position of the given group.\n * ```c\n * void nk_group_get_scroll(struct nk_context*, const char *id, nk_uint *x_offset, nk_uint *y_offset);\n * ```\n *\n * Parameter    | Description\n * -------------|-----------------------------------------------------------\n * \\param[in] ctx      | Must point to an previously initialized `nk_context` struct\n * \\param[in] id       | The id of the group to get the scroll position of\n * \\param[in] x_offset | A pointer to the x offset output (or NULL to ignore)\n * \\param[in] y_offset | A pointer to the y offset output (or NULL to ignore)\n */\nNK_API void nk_group_get_scroll(struct nk_context*, const char *id, nk_uint *x_offset, nk_uint *y_offset);\n\n/**\n * # # nk_group_set_scroll\n * Sets the scroll position of the given group.\n * ```c\n * void nk_group_set_scroll(struct nk_context*, const char *id, nk_uint x_offset, nk_uint y_offset);\n * ```\n *\n * Parameter    | Description\n * -------------|-----------------------------------------------------------\n * \\param[in] ctx      | Must point to an previously initialized `nk_context` struct\n * \\param[in] id       | The id of the group to scroll\n * \\param[in] x_offset | The x offset to scroll to\n * \\param[in] y_offset | The y offset to scroll to\n */\nNK_API void nk_group_set_scroll(struct nk_context*, const char *id, nk_uint x_offset, nk_uint y_offset);\n\n/* =============================================================================\n *\n *                                  TREE\n *\n * =============================================================================*/\n/**\n * \\page Tree\n * Trees represent two different concept. First the concept of a collapsible\n * UI section that can be either in a hidden or visible state. They allow the UI\n * user to selectively minimize the current set of visible UI to comprehend.\n * The second concept are tree widgets for visual UI representation of trees.<br /><br />\n *\n * Trees thereby can be nested for tree representations and multiple nested\n * collapsible UI sections. All trees are started by calling of the\n * `nk_tree_xxx_push_tree` functions and ended by calling one of the\n * `nk_tree_xxx_pop_xxx()` functions. Each starting functions takes a title label\n * and optionally an image to be displayed and the initial collapse state from\n * the nk_collapse_states section.<br /><br />\n *\n * The runtime state of the tree is either stored outside the library by the caller\n * or inside which requires a unique ID. The unique ID can either be generated\n * automatically from `__FILE__` and `__LINE__` with function `nk_tree_push`,\n * by `__FILE__` and a user provided ID generated for example by loop index with\n * function `nk_tree_push_id` or completely provided from outside by user with\n * function `nk_tree_push_hashed`.\n *\n * # Usage\n * To create a tree you have to call one of the seven `nk_tree_xxx_push_xxx`\n * functions to start a collapsible UI section and `nk_tree_xxx_pop` to mark the\n * end.\n * Each starting function will either return `false(0)` if the tree is collapsed\n * or hidden and therefore does not need to be filled with content or `true(1)`\n * if visible and required to be filled.\n *\n * !!! Note\n *     The tree header does not require and layouting function and instead\n *     calculates a auto height based on the currently used font size\n *\n * The tree ending functions only need to be called if the tree content is\n * actually visible. So make sure the tree push function is guarded by `if`\n * and the pop call is only taken if the tree is visible.\n *\n * ```c\n * if (nk_tree_push(ctx, NK_TREE_TAB, \"Tree\", NK_MINIMIZED)) {\n *     nk_layout_row_dynamic(...);\n *     nk_widget(...);\n *     nk_tree_pop(ctx);\n * }\n * ```\n *\n * # Reference\n * Function                    | Description\n * ----------------------------|-------------------------------------------\n * nk_tree_push                | Start a collapsible UI section with internal state management\n * nk_tree_push_id             | Start a collapsible UI section with internal state management callable in a look\n * nk_tree_push_hashed         | Start a collapsible UI section with internal state management with full control over internal unique ID use to store state\n * nk_tree_image_push          | Start a collapsible UI section with image and label header\n * nk_tree_image_push_id       | Start a collapsible UI section with image and label header and internal state management callable in a look\n * nk_tree_image_push_hashed   | Start a collapsible UI section with image and label header and internal state management with full control over internal unique ID use to store state\n * nk_tree_pop                 | Ends a collapsible UI section\n * nk_tree_state_push          | Start a collapsible UI section with external state management\n * nk_tree_state_image_push    | Start a collapsible UI section with image and label header and external state management\n * nk_tree_state_pop           | Ends a collapsabale UI section\n *\n * # nk_tree_type\n * Flag            | Description\n * ----------------|----------------------------------------\n * NK_TREE_NODE    | Highlighted tree header to mark a collapsible UI section\n * NK_TREE_TAB     | Non-highlighted tree header closer to tree representations\n */\n\n/**\n * # # nk_tree_push\n * Starts a collapsible UI section with internal state management\n * !!! \\warning\n *     To keep track of the runtime tree collapsible state this function uses\n *     defines `__FILE__` and `__LINE__` to generate a unique ID. If you want\n *     to call this function in a loop please use `nk_tree_push_id` or\n *     `nk_tree_push_hashed` instead.\n *\n * ```c\n * #define nk_tree_push(ctx, type, title, state)\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Initial tree state value out of nk_collapse_states\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\n#define nk_tree_push(ctx, type, title, state) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__)\n\n/**\n * # # nk_tree_push_id\n * Starts a collapsible UI section with internal state management callable in a look\n * ```c\n * #define nk_tree_push_id(ctx, type, title, state, id)\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Initial tree state value out of nk_collapse_states\n * \\param[in] id      | Loop counter index if this function is called in a loop\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\n#define nk_tree_push_id(ctx, type, title, state, id) nk_tree_push_hashed(ctx, type, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id)\n\n/**\n * # # nk_tree_push_hashed\n * Start a collapsible UI section with internal state management with full\n * control over internal unique ID used to store state\n * ```c\n * nk_bool nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Initial tree state value out of nk_collapse_states\n * \\param[in] hash    | Memory block or string to generate the ID from\n * \\param[in] len     | Size of passed memory block or string in __hash__\n * \\param[in] seed    | Seeding value if this function is called in a loop or default to `0`\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_tree_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);\n\n/**\n * # # nk_tree_image_push\n * Start a collapsible UI section with image and label header\n * !!! \\warning\n *     To keep track of the runtime tree collapsible state this function uses\n *     defines `__FILE__` and `__LINE__` to generate a unique ID. If you want\n *     to call this function in a loop please use `nk_tree_image_push_id` or\n *     `nk_tree_image_push_hashed` instead.\n *\n * ```c\n * #define nk_tree_image_push(ctx, type, img, title, state)\n * ```\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] img     | Image to display inside the header on the left of the label\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Initial tree state value out of nk_collapse_states\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\n#define nk_tree_image_push(ctx, type, img, title, state) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__)\n\n/**\n * # # nk_tree_image_push_id\n * Start a collapsible UI section with image and label header and internal state\n * management callable in a look\n *\n * ```c\n * #define nk_tree_image_push_id(ctx, type, img, title, state, id)\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] img     | Image to display inside the header on the left of the label\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Initial tree state value out of nk_collapse_states\n * \\param[in] id      | Loop counter index if this function is called in a loop\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\n#define nk_tree_image_push_id(ctx, type, img, title, state, id) nk_tree_image_push_hashed(ctx, type, img, title, state, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id)\n\n/**\n * # # nk_tree_image_push_hashed\n * Start a collapsible UI section with internal state management with full\n * control over internal unique ID used to store state\n * ```c\n * nk_bool nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] img     | Image to display inside the header on the left of the label\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Initial tree state value out of nk_collapse_states\n * \\param[in] hash    | Memory block or string to generate the ID from\n * \\param[in] len     | Size of passed memory block or string in __hash__\n * \\param[in] seed    | Seeding value if this function is called in a loop or default to `0`\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_tree_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, const char *hash, int len,int seed);\n\n/**\n * # # nk_tree_pop\n * Ends a collapsabale UI section\n * ```c\n * void nk_tree_pop(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx`\n */\nNK_API void nk_tree_pop(struct nk_context*);\n\n/**\n * # # nk_tree_state_push\n * Start a collapsible UI section with external state management\n * ```c\n * nk_bool nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx`\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Persistent state to update\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_tree_state_push(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states *state);\n\n/**\n * # # nk_tree_state_image_push\n * Start a collapsible UI section with image and label header and external state management\n * ```c\n * nk_bool nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx`\n * \\param[in] img     | Image to display inside the header on the left of the label\n * \\param[in] type    | Value from the nk_tree_type section to visually mark a tree node header as either a collapseable UI section or tree node\n * \\param[in] title   | Label printed in the tree header\n * \\param[in] state   | Persistent state to update\n *\n * \\returns `true(1)` if visible and fillable with widgets or `false(0)` otherwise\n */\nNK_API nk_bool nk_tree_state_image_push(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states *state);\n\n/**\n * # # nk_tree_state_pop\n * Ends a collapsabale UI section\n * ```c\n * void nk_tree_state_pop(struct nk_context*);\n * ```\n *\n * Parameter   | Description\n * ------------|-----------------------------------------------------------\n * \\param[in] ctx     | Must point to an previously initialized `nk_context` struct after calling `nk_tree_xxx_push_xxx`\n */\nNK_API void nk_tree_state_pop(struct nk_context*);\n\n#define nk_tree_element_push(ctx, type, title, state, sel) nk_tree_element_push_hashed(ctx, type, title, state, sel, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),__LINE__)\n#define nk_tree_element_push_id(ctx, type, title, state, sel, id) nk_tree_element_push_hashed(ctx, type, title, state, sel, NK_FILE_LINE,nk_strlen(NK_FILE_LINE),id)\nNK_API nk_bool nk_tree_element_push_hashed(struct nk_context*, enum nk_tree_type, const char *title, enum nk_collapse_states initial_state, nk_bool *selected, const char *hash, int len, int seed);\nNK_API nk_bool nk_tree_element_image_push_hashed(struct nk_context*, enum nk_tree_type, struct nk_image, const char *title, enum nk_collapse_states initial_state, nk_bool *selected, const char *hash, int len,int seed);\nNK_API void nk_tree_element_pop(struct nk_context*);\n\n/* =============================================================================\n *\n *                                  LIST VIEW\n *\n * ============================================================================= */\nstruct nk_list_view {\n/* public: */\n    int begin, end, count;\n/* private: */\n    int total_height;\n    struct nk_context *ctx;\n    nk_uint *scroll_pointer;\n    nk_uint scroll_value;\n};\nNK_API nk_bool nk_list_view_begin(struct nk_context*, struct nk_list_view *out, const char *id, nk_flags, int row_height, int row_count);\nNK_API void nk_list_view_end(struct nk_list_view*);\n/* =============================================================================\n *\n *                                  WIDGET\n *\n * ============================================================================= */\nenum nk_widget_layout_states {\n    NK_WIDGET_INVALID, /**< The widget cannot be seen and is completely out of view */\n    NK_WIDGET_VALID,   /**< The widget is completely inside the window and can be updated and drawn */\n    NK_WIDGET_ROM,     /**< The widget is partially visible and cannot be updated */\n    NK_WIDGET_DISABLED /**< The widget is manually disabled and acts like NK_WIDGET_ROM */\n};\nenum nk_widget_states {\n    NK_WIDGET_STATE_MODIFIED    = NK_FLAG(1),\n    NK_WIDGET_STATE_INACTIVE    = NK_FLAG(2), /**!< widget is neither active nor hovered */\n    NK_WIDGET_STATE_ENTERED     = NK_FLAG(3), /**!< widget has been hovered on the current frame */\n    NK_WIDGET_STATE_HOVER       = NK_FLAG(4), /**!< widget is being hovered */\n    NK_WIDGET_STATE_ACTIVED     = NK_FLAG(5),/**!< widget is currently activated */\n    NK_WIDGET_STATE_LEFT        = NK_FLAG(6), /**!< widget is from this frame on not hovered anymore */\n    NK_WIDGET_STATE_HOVERED     = NK_WIDGET_STATE_HOVER|NK_WIDGET_STATE_MODIFIED, /**!< widget is being hovered */\n    NK_WIDGET_STATE_ACTIVE      = NK_WIDGET_STATE_ACTIVED|NK_WIDGET_STATE_MODIFIED /**!< widget is currently activated */\n};\nNK_API enum nk_widget_layout_states nk_widget(struct nk_rect*, const struct nk_context*);\nNK_API enum nk_widget_layout_states nk_widget_fitting(struct nk_rect*, const struct nk_context*, struct nk_vec2);\nNK_API struct nk_rect nk_widget_bounds(const struct nk_context*);\nNK_API struct nk_vec2 nk_widget_position(const struct nk_context*);\nNK_API struct nk_vec2 nk_widget_size(const struct nk_context*);\nNK_API float nk_widget_width(const struct nk_context*);\nNK_API float nk_widget_height(const struct nk_context*);\nNK_API nk_bool nk_widget_is_hovered(const struct nk_context*);\nNK_API nk_bool nk_widget_is_mouse_clicked(const struct nk_context*, enum nk_buttons);\nNK_API nk_bool nk_widget_has_mouse_click_down(const struct nk_context*, enum nk_buttons, nk_bool down);\nNK_API void nk_spacing(struct nk_context*, int cols);\nNK_API void nk_widget_disable_begin(struct nk_context* ctx);\nNK_API void nk_widget_disable_end(struct nk_context* ctx);\n/* =============================================================================\n *\n *                                  TEXT\n *\n * ============================================================================= */\nenum nk_text_align {\n    NK_TEXT_ALIGN_LEFT        = 0x01,\n    NK_TEXT_ALIGN_CENTERED    = 0x02,\n    NK_TEXT_ALIGN_RIGHT       = 0x04,\n    NK_TEXT_ALIGN_TOP         = 0x08,\n    NK_TEXT_ALIGN_MIDDLE      = 0x10,\n    NK_TEXT_ALIGN_BOTTOM      = 0x20\n};\nenum nk_text_alignment {\n    NK_TEXT_LEFT        = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_LEFT,\n    NK_TEXT_CENTERED    = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_CENTERED,\n    NK_TEXT_RIGHT       = NK_TEXT_ALIGN_MIDDLE|NK_TEXT_ALIGN_RIGHT\n};\nNK_API void nk_text(struct nk_context*, const char*, int, nk_flags);\nNK_API void nk_text_colored(struct nk_context*, const char*, int, nk_flags, struct nk_color);\nNK_API void nk_text_wrap(struct nk_context*, const char*, int);\nNK_API void nk_text_wrap_colored(struct nk_context*, const char*, int, struct nk_color);\nNK_API void nk_label(struct nk_context*, const char*, nk_flags align);\nNK_API void nk_label_colored(struct nk_context*, const char*, nk_flags align, struct nk_color);\nNK_API void nk_label_wrap(struct nk_context*, const char*);\nNK_API void nk_label_colored_wrap(struct nk_context*, const char*, struct nk_color);\nNK_API void nk_image(struct nk_context*, struct nk_image);\nNK_API void nk_image_color(struct nk_context*, struct nk_image, struct nk_color);\n#ifdef NK_INCLUDE_STANDARD_VARARGS\nNK_API void nk_labelf(struct nk_context*, nk_flags, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(3);\nNK_API void nk_labelf_colored(struct nk_context*, nk_flags, struct nk_color, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(4);\nNK_API void nk_labelf_wrap(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(2);\nNK_API void nk_labelf_colored_wrap(struct nk_context*, struct nk_color, NK_PRINTF_FORMAT_STRING const char*,...) NK_PRINTF_VARARG_FUNC(3);\nNK_API void nk_labelfv(struct nk_context*, nk_flags, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(3);\nNK_API void nk_labelfv_colored(struct nk_context*, nk_flags, struct nk_color, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(4);\nNK_API void nk_labelfv_wrap(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2);\nNK_API void nk_labelfv_colored_wrap(struct nk_context*, struct nk_color, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(3);\nNK_API void nk_value_bool(struct nk_context*, const char *prefix, int);\nNK_API void nk_value_int(struct nk_context*, const char *prefix, int);\nNK_API void nk_value_uint(struct nk_context*, const char *prefix, unsigned int);\nNK_API void nk_value_float(struct nk_context*, const char *prefix, float);\nNK_API void nk_value_color_byte(struct nk_context*, const char *prefix, struct nk_color);\nNK_API void nk_value_color_float(struct nk_context*, const char *prefix, struct nk_color);\nNK_API void nk_value_color_hex(struct nk_context*, const char *prefix, struct nk_color);\n#endif\n/* =============================================================================\n *\n *                                  BUTTON\n *\n * ============================================================================= */\nNK_API nk_bool nk_button_text(struct nk_context*, const char *title, int len);\nNK_API nk_bool nk_button_label(struct nk_context*, const char *title);\nNK_API nk_bool nk_button_color(struct nk_context*, struct nk_color);\nNK_API nk_bool nk_button_symbol(struct nk_context*, enum nk_symbol_type);\nNK_API nk_bool nk_button_image(struct nk_context*, struct nk_image img);\nNK_API nk_bool nk_button_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags text_alignment);\nNK_API nk_bool nk_button_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);\nNK_API nk_bool nk_button_image_label(struct nk_context*, struct nk_image img, const char*, nk_flags text_alignment);\nNK_API nk_bool nk_button_image_text(struct nk_context*, struct nk_image img, const char*, int, nk_flags alignment);\nNK_API nk_bool nk_button_text_styled(struct nk_context*, const struct nk_style_button*, const char *title, int len);\nNK_API nk_bool nk_button_label_styled(struct nk_context*, const struct nk_style_button*, const char *title);\nNK_API nk_bool nk_button_symbol_styled(struct nk_context*, const struct nk_style_button*, enum nk_symbol_type);\nNK_API nk_bool nk_button_image_styled(struct nk_context*, const struct nk_style_button*, struct nk_image img);\nNK_API nk_bool nk_button_symbol_text_styled(struct nk_context*,const struct nk_style_button*, enum nk_symbol_type, const char*, int, nk_flags alignment);\nNK_API nk_bool nk_button_symbol_label_styled(struct nk_context *ctx, const struct nk_style_button *style, enum nk_symbol_type symbol, const char *title, nk_flags align);\nNK_API nk_bool nk_button_image_label_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, nk_flags text_alignment);\nNK_API nk_bool nk_button_image_text_styled(struct nk_context*,const struct nk_style_button*, struct nk_image img, const char*, int, nk_flags alignment);\nNK_API void nk_button_set_behavior(struct nk_context*, enum nk_button_behavior);\nNK_API nk_bool nk_button_push_behavior(struct nk_context*, enum nk_button_behavior);\nNK_API nk_bool nk_button_pop_behavior(struct nk_context*);\n/* =============================================================================\n *\n *                                  CHECKBOX\n *\n * ============================================================================= */\nNK_API nk_bool nk_check_label(struct nk_context*, const char*, nk_bool active);\nNK_API nk_bool nk_check_text(struct nk_context*, const char*, int, nk_bool active);\nNK_API nk_bool nk_check_text_align(struct nk_context*, const char*, int, nk_bool active, nk_flags widget_alignment, nk_flags text_alignment);\nNK_API unsigned nk_check_flags_label(struct nk_context*, const char*, unsigned int flags, unsigned int value);\nNK_API unsigned nk_check_flags_text(struct nk_context*, const char*, int, unsigned int flags, unsigned int value);\nNK_API nk_bool nk_checkbox_label(struct nk_context*, const char*, nk_bool *active);\nNK_API nk_bool nk_checkbox_label_align(struct nk_context *ctx, const char *label, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment);\nNK_API nk_bool nk_checkbox_text(struct nk_context*, const char*, int, nk_bool *active);\nNK_API nk_bool nk_checkbox_text_align(struct nk_context *ctx, const char *text, int len, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment);\nNK_API nk_bool nk_checkbox_flags_label(struct nk_context*, const char*, unsigned int *flags, unsigned int value);\nNK_API nk_bool nk_checkbox_flags_text(struct nk_context*, const char*, int, unsigned int *flags, unsigned int value);\n/* =============================================================================\n *\n *                                  RADIO BUTTON\n *\n * ============================================================================= */\nNK_API nk_bool nk_radio_label(struct nk_context*, const char*, nk_bool *active);\nNK_API nk_bool nk_radio_label_align(struct nk_context *ctx, const char *label, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment);\nNK_API nk_bool nk_radio_text(struct nk_context*, const char*, int, nk_bool *active);\nNK_API nk_bool nk_radio_text_align(struct nk_context *ctx, const char *text, int len, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment);\nNK_API nk_bool nk_option_label(struct nk_context*, const char*, nk_bool active);\nNK_API nk_bool nk_option_label_align(struct nk_context *ctx, const char *label, nk_bool active, nk_flags widget_alignment, nk_flags text_alignment);\nNK_API nk_bool nk_option_text(struct nk_context*, const char*, int, nk_bool active);\nNK_API nk_bool nk_option_text_align(struct nk_context *ctx, const char *text, int len, nk_bool is_active, nk_flags widget_alignment, nk_flags text_alignment);\n/* =============================================================================\n *\n *                                  SELECTABLE\n *\n * ============================================================================= */\nNK_API nk_bool nk_selectable_label(struct nk_context*, const char*, nk_flags align, nk_bool *value);\nNK_API nk_bool nk_selectable_text(struct nk_context*, const char*, int, nk_flags align, nk_bool *value);\nNK_API nk_bool nk_selectable_image_label(struct nk_context*,struct nk_image,  const char*, nk_flags align, nk_bool *value);\nNK_API nk_bool nk_selectable_image_text(struct nk_context*,struct nk_image, const char*, int, nk_flags align, nk_bool *value);\nNK_API nk_bool nk_selectable_symbol_label(struct nk_context*,enum nk_symbol_type,  const char*, nk_flags align, nk_bool *value);\nNK_API nk_bool nk_selectable_symbol_text(struct nk_context*,enum nk_symbol_type, const char*, int, nk_flags align, nk_bool *value);\n\nNK_API nk_bool nk_select_label(struct nk_context*, const char*, nk_flags align, nk_bool value);\nNK_API nk_bool nk_select_text(struct nk_context*, const char*, int, nk_flags align, nk_bool value);\nNK_API nk_bool nk_select_image_label(struct nk_context*, struct nk_image,const char*, nk_flags align, nk_bool value);\nNK_API nk_bool nk_select_image_text(struct nk_context*, struct nk_image,const char*, int, nk_flags align, nk_bool value);\nNK_API nk_bool nk_select_symbol_label(struct nk_context*,enum nk_symbol_type,  const char*, nk_flags align, nk_bool value);\nNK_API nk_bool nk_select_symbol_text(struct nk_context*,enum nk_symbol_type, const char*, int, nk_flags align, nk_bool value);\n\n/* =============================================================================\n *\n *                                  SLIDER\n *\n * ============================================================================= */\nNK_API float nk_slide_float(struct nk_context*, float min, float val, float max, float step);\nNK_API int nk_slide_int(struct nk_context*, int min, int val, int max, int step);\nNK_API nk_bool nk_slider_float(struct nk_context*, float min, float *val, float max, float step);\nNK_API nk_bool nk_slider_int(struct nk_context*, int min, int *val, int max, int step);\n\n/* =============================================================================\n *\n *                                   KNOB\n *\n * ============================================================================= */\nNK_API nk_bool nk_knob_float(struct nk_context*, float min, float *val, float max, float step, enum nk_heading zero_direction, float dead_zone_degrees);\nNK_API nk_bool nk_knob_int(struct nk_context*, int min, int *val, int max, int step, enum nk_heading zero_direction, float dead_zone_degrees);\n\n/* =============================================================================\n *\n *                                  PROGRESSBAR\n *\n * ============================================================================= */\nNK_API nk_bool nk_progress(struct nk_context*, nk_size *cur, nk_size max, nk_bool modifyable);\nNK_API nk_size nk_prog(struct nk_context*, nk_size cur, nk_size max, nk_bool modifyable);\n\n/* =============================================================================\n *\n *                                  COLOR PICKER\n *\n * ============================================================================= */\nNK_API struct nk_colorf nk_color_picker(struct nk_context*, struct nk_colorf, enum nk_color_format);\nNK_API nk_bool nk_color_pick(struct nk_context*, struct nk_colorf*, enum nk_color_format);\n/* =============================================================================\n *\n *                                  PROPERTIES\n *\n * =============================================================================*/\n/**\n * \\page Properties\n * Properties are the main value modification widgets in Nuklear. Changing a value\n * can be achieved by dragging, adding/removing incremental steps on button click\n * or by directly typing a number.\n *\n * # Usage\n * Each property requires a unique name for identification that is also used for\n * displaying a label. If you want to use the same name multiple times make sure\n * add a '#' before your name. The '#' will not be shown but will generate a\n * unique ID. Each property also takes in a minimum and maximum value. If you want\n * to make use of the complete number range of a type just use the provided\n * type limits from `limits.h`. For example `INT_MIN` and `INT_MAX` for\n * `nk_property_int` and `nk_propertyi`. In additional each property takes in\n * a increment value that will be added or subtracted if either the increment\n * decrement button is clicked. Finally there is a value for increment per pixel\n * dragged that is added or subtracted from the value.\n *\n * ```c\n * int value = 0;\n * struct nk_context ctx;\n * nk_init_xxx(&ctx, ...);\n * while (1) {\n *     // Input\n *     Event evt;\n *     nk_input_begin(&ctx);\n *     while (GetEvent(&evt)) {\n *         if (evt.type == MOUSE_MOVE)\n *             nk_input_motion(&ctx, evt.motion.x, evt.motion.y);\n *         else if (evt.type == [...]) {\n *             nk_input_xxx(...);\n *         }\n *     }\n *     nk_input_end(&ctx);\n *     //\n *     // Window\n *     if (nk_begin_xxx(...) {\n *         // Property\n *         nk_layout_row_dynamic(...);\n *         nk_property_int(ctx, \"ID\", INT_MIN, &value, INT_MAX, 1, 1);\n *     }\n *     nk_end(ctx);\n *     //\n *     // Draw\n *     const struct nk_command *cmd = 0;\n *     nk_foreach(cmd, &ctx) {\n *     switch (cmd->type) {\n *     case NK_COMMAND_LINE:\n *         your_draw_line_function(...)\n *         break;\n *     case NK_COMMAND_RECT\n *         your_draw_rect_function(...)\n *         break;\n *     case ...:\n *         // [...]\n *     }\n *     nk_clear(&ctx);\n * }\n * nk_free(&ctx);\n * ```\n *\n * # Reference\n * Function            | Description\n * --------------------|-------------------------------------------\n * \\ref nk_property_int     | Integer property directly modifying a passed in value\n * \\ref nk_property_float   | Float property directly modifying a passed in value\n * \\ref nk_property_double  | Double property directly modifying a passed in value\n * \\ref nk_propertyi        | Integer property returning the modified int value\n * \\ref nk_propertyf        | Float property returning the modified float value\n * \\ref nk_propertyd        | Double property returning the modified double value\n *\n\n * # # nk_property_int\n * Integer property directly modifying a passed in value\n * !!! \\warning\n *     To generate a unique property ID using the same label make sure to insert\n *     a `#` at the beginning. It will not be shown but guarantees correct behavior.\n *\n * ```c\n * nk_bool nk_property_int(struct nk_context *ctx, const char *name, int min, int *val, int max, int step, float inc_per_pixel);\n * ```\n *\n * Parameter           | Description\n * --------------------|-----------------------------------------------------------\n * \\param[in] ctx             | Must point to an previously initialized `nk_context` struct after calling a layouting function\n * \\param[in] name            | String used both as a label as well as a unique identifier\n * \\param[in] min             | Minimum value not allowed to be underflown\n * \\param[in] val             | Integer pointer to be modified\n * \\param[in] max             | Maximum value not allowed to be overflown\n * \\param[in] step            | Increment added and subtracted on increment and decrement button\n * \\param[in] inc_per_pixel   | Value per pixel added or subtracted on dragging\n *\n * \\returns `true(1)` if the value changed\n */\nNK_API nk_bool nk_property_int(struct nk_context*, const char *name, int min, int *val, int max, int step, float inc_per_pixel);\n\n/**\n * # # nk_property_float\n * Float property directly modifying a passed in value\n * !!! \\warning\n *     To generate a unique property ID using the same label make sure to insert\n *     a `#` at the beginning. It will not be shown but guarantees correct behavior.\n *\n * ```c\n * nk_bool nk_property_float(struct nk_context *ctx, const char *name, float min, float *val, float max, float step, float inc_per_pixel);\n * ```\n *\n * Parameter           | Description\n * --------------------|-----------------------------------------------------------\n * \\param[in] ctx             | Must point to an previously initialized `nk_context` struct after calling a layouting function\n * \\param[in] name            | String used both as a label as well as a unique identifier\n * \\param[in] min             | Minimum value not allowed to be underflown\n * \\param[in] val             | Float pointer to be modified\n * \\param[in] max             | Maximum value not allowed to be overflown\n * \\param[in] step            | Increment added and subtracted on increment and decrement button\n * \\param[in] inc_per_pixel   | Value per pixel added or subtracted on dragging\n *\n * \\returns `true(1)` if the value changed\n */\nNK_API nk_bool nk_property_float(struct nk_context*, const char *name, float min, float *val, float max, float step, float inc_per_pixel);\n\n/**\n * # # nk_property_double\n * Double property directly modifying a passed in value\n * !!! \\warning\n *     To generate a unique property ID using the same label make sure to insert\n *     a `#` at the beginning. It will not be shown but guarantees correct behavior.\n *\n * ```c\n * nk_bool nk_property_double(struct nk_context *ctx, const char *name, double min, double *val, double max, double step, double inc_per_pixel);\n * ```\n *\n * Parameter           | Description\n * --------------------|-----------------------------------------------------------\n * \\param[in] ctx             | Must point to an previously initialized `nk_context` struct after calling a layouting function\n * \\param[in] name            | String used both as a label as well as a unique identifier\n * \\param[in] min             | Minimum value not allowed to be underflown\n * \\param[in] val             | Double pointer to be modified\n * \\param[in] max             | Maximum value not allowed to be overflown\n * \\param[in] step            | Increment added and subtracted on increment and decrement button\n * \\param[in] inc_per_pixel   | Value per pixel added or subtracted on dragging\n *\n * \\returns `true(1)` if the value changed\n */\nNK_API nk_bool nk_property_double(struct nk_context*, const char *name, double min, double *val, double max, double step, float inc_per_pixel);\n\n/**\n * # # nk_propertyi\n * Integer property modifying a passed in value and returning the new value\n * !!! \\warning\n *     To generate a unique property ID using the same label make sure to insert\n *     a `#` at the beginning. It will not be shown but guarantees correct behavior.\n *\n * ```c\n * int nk_propertyi(struct nk_context *ctx, const char *name, int min, int val, int max, int step, float inc_per_pixel);\n * ```\n *\n * \\param[in] ctx              Must point to an previously initialized `nk_context` struct after calling a layouting function\n * \\param[in] name             String used both as a label as well as a unique identifier\n * \\param[in] min              Minimum value not allowed to be underflown\n * \\param[in] val              Current integer value to be modified and returned\n * \\param[in] max              Maximum value not allowed to be overflown\n * \\param[in] step             Increment added and subtracted on increment and decrement button\n * \\param[in] inc_per_pixel    Value per pixel added or subtracted on dragging\n *\n * \\returns the new modified integer value\n */\nNK_API int nk_propertyi(struct nk_context*, const char *name, int min, int val, int max, int step, float inc_per_pixel);\n\n/**\n * # # nk_propertyf\n * Float property modifying a passed in value and returning the new value\n * !!! \\warning\n *     To generate a unique property ID using the same label make sure to insert\n *     a `#` at the beginning. It will not be shown but guarantees correct behavior.\n *\n * ```c\n * float nk_propertyf(struct nk_context *ctx, const char *name, float min, float val, float max, float step, float inc_per_pixel);\n * ```\n *\n * \\param[in] ctx              Must point to an previously initialized `nk_context` struct after calling a layouting function\n * \\param[in] name             String used both as a label as well as a unique identifier\n * \\param[in] min              Minimum value not allowed to be underflown\n * \\param[in] val              Current float value to be modified and returned\n * \\param[in] max              Maximum value not allowed to be overflown\n * \\param[in] step             Increment added and subtracted on increment and decrement button\n * \\param[in] inc_per_pixel    Value per pixel added or subtracted on dragging\n *\n * \\returns the new modified float value\n */\nNK_API float nk_propertyf(struct nk_context*, const char *name, float min, float val, float max, float step, float inc_per_pixel);\n\n/**\n * # # nk_propertyd\n * Float property modifying a passed in value and returning the new value\n * !!! \\warning\n *     To generate a unique property ID using the same label make sure to insert\n *     a `#` at the beginning. It will not be shown but guarantees correct behavior.\n *\n * ```c\n * float nk_propertyd(struct nk_context *ctx, const char *name, double min, double val, double max, double step, double inc_per_pixel);\n * ```\n *\n * \\param[in] ctx              Must point to an previously initialized `nk_context` struct after calling a layouting function\n * \\param[in] name             String used both as a label as well as a unique identifier\n * \\param[in] min              Minimum value not allowed to be underflown\n * \\param[in] val              Current double value to be modified and returned\n * \\param[in] max              Maximum value not allowed to be overflown\n * \\param[in] step             Increment added and subtracted on increment and decrement button\n * \\param[in] inc_per_pixel    Value per pixel added or subtracted on dragging\n *\n * \\returns the new modified double value\n */\nNK_API double nk_propertyd(struct nk_context*, const char *name, double min, double val, double max, double step, float inc_per_pixel);\n\n/* =============================================================================\n *\n *                                  TEXT EDIT\n *\n * ============================================================================= */\nenum nk_edit_flags {\n    NK_EDIT_DEFAULT                 = 0,\n    NK_EDIT_READ_ONLY               = NK_FLAG(0),\n    NK_EDIT_AUTO_SELECT             = NK_FLAG(1),\n    NK_EDIT_SIG_ENTER               = NK_FLAG(2),\n    NK_EDIT_ALLOW_TAB               = NK_FLAG(3),\n    NK_EDIT_NO_CURSOR               = NK_FLAG(4),\n    NK_EDIT_SELECTABLE              = NK_FLAG(5),\n    NK_EDIT_CLIPBOARD               = NK_FLAG(6),\n    NK_EDIT_CTRL_ENTER_NEWLINE      = NK_FLAG(7),\n    NK_EDIT_NO_HORIZONTAL_SCROLL    = NK_FLAG(8),\n    NK_EDIT_ALWAYS_INSERT_MODE      = NK_FLAG(9),\n    NK_EDIT_MULTILINE               = NK_FLAG(10),\n    NK_EDIT_GOTO_END_ON_ACTIVATE    = NK_FLAG(11)\n};\nenum nk_edit_types {\n    NK_EDIT_SIMPLE  = NK_EDIT_ALWAYS_INSERT_MODE,\n    NK_EDIT_FIELD   = NK_EDIT_SIMPLE|NK_EDIT_SELECTABLE|NK_EDIT_CLIPBOARD,\n    NK_EDIT_BOX     = NK_EDIT_ALWAYS_INSERT_MODE| NK_EDIT_SELECTABLE| NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB|NK_EDIT_CLIPBOARD,\n    NK_EDIT_EDITOR  = NK_EDIT_SELECTABLE|NK_EDIT_MULTILINE|NK_EDIT_ALLOW_TAB| NK_EDIT_CLIPBOARD\n};\nenum nk_edit_events {\n    NK_EDIT_ACTIVE      = NK_FLAG(0), /**!< edit widget is currently being modified */\n    NK_EDIT_INACTIVE    = NK_FLAG(1), /**!< edit widget is not active and is not being modified */\n    NK_EDIT_ACTIVATED   = NK_FLAG(2), /**!< edit widget went from state inactive to state active */\n    NK_EDIT_DEACTIVATED = NK_FLAG(3), /**!< edit widget went from state active to state inactive */\n    NK_EDIT_COMMITED    = NK_FLAG(4)  /**!< edit widget has received an enter and lost focus */\n};\nNK_API nk_flags nk_edit_string(struct nk_context*, nk_flags, char *buffer, int *len, int max, nk_plugin_filter);\nNK_API nk_flags nk_edit_string_zero_terminated(struct nk_context*, nk_flags, char *buffer, int max, nk_plugin_filter);\nNK_API nk_flags nk_edit_buffer(struct nk_context*, nk_flags, struct nk_text_edit*, nk_plugin_filter);\nNK_API void nk_edit_focus(struct nk_context*, nk_flags flags);\nNK_API void nk_edit_unfocus(struct nk_context*);\n/* =============================================================================\n *\n *                                  CHART\n *\n * ============================================================================= */\nNK_API nk_bool nk_chart_begin(struct nk_context*, enum nk_chart_type, int num, float min, float max);\nNK_API nk_bool nk_chart_begin_colored(struct nk_context*, enum nk_chart_type, struct nk_color, struct nk_color active, int num, float min, float max);\nNK_API void nk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type, int count, float min_value, float max_value);\nNK_API void nk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type, struct nk_color, struct nk_color active, int count, float min_value, float max_value);\nNK_API nk_flags nk_chart_push(struct nk_context*, float);\nNK_API nk_flags nk_chart_push_slot(struct nk_context*, float, int);\nNK_API void nk_chart_end(struct nk_context*);\nNK_API void nk_plot(struct nk_context*, enum nk_chart_type, const float *values, int count, int offset);\nNK_API void nk_plot_function(struct nk_context*, enum nk_chart_type, void *userdata, float(*value_getter)(void* user, int index), int count, int offset);\n/* =============================================================================\n *\n *                                  POPUP\n *\n * ============================================================================= */\nNK_API nk_bool nk_popup_begin(struct nk_context*, enum nk_popup_type, const char*, nk_flags, struct nk_rect bounds);\nNK_API void nk_popup_close(struct nk_context*);\nNK_API void nk_popup_end(struct nk_context*);\nNK_API void nk_popup_get_scroll(const struct nk_context*, nk_uint *offset_x, nk_uint *offset_y);\nNK_API void nk_popup_set_scroll(struct nk_context*, nk_uint offset_x, nk_uint offset_y);\n/* =============================================================================\n *\n *                                  COMBOBOX\n *\n * ============================================================================= */\nNK_API int nk_combo(struct nk_context*, const char *const *items, int count, int selected, int item_height, struct nk_vec2 size);\nNK_API int nk_combo_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int selected, int count, int item_height, struct nk_vec2 size);\nNK_API int nk_combo_string(struct nk_context*, const char *items_separated_by_zeros, int selected, int count, int item_height, struct nk_vec2 size);\nNK_API int nk_combo_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void *userdata, int selected, int count, int item_height, struct nk_vec2 size);\nNK_API nk_bool nk_combobox(struct nk_context*, const char *const *items, int count, int *selected, int item_height, struct nk_vec2 size);\nNK_API nk_bool nk_combobox_string(struct nk_context*, const char *items_separated_by_zeros, int *selected, int count, int item_height, struct nk_vec2 size);\nNK_API nk_bool nk_combobox_separator(struct nk_context*, const char *items_separated_by_separator, int separator, int *selected, int count, int item_height, struct nk_vec2 size);\nNK_API nk_bool nk_combobox_callback(struct nk_context*, void(*item_getter)(void*, int, const char**), void*, int *selected, int count, int item_height, struct nk_vec2 size);\n/* =============================================================================\n *\n *                                  ABSTRACT COMBOBOX\n *\n * ============================================================================= */\nNK_API nk_bool nk_combo_begin_text(struct nk_context*, const char *selected, int, struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_label(struct nk_context*, const char *selected, struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_color(struct nk_context*, struct nk_color color, struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_symbol(struct nk_context*,  enum nk_symbol_type,  struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_symbol_label(struct nk_context*, const char *selected, enum nk_symbol_type, struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_symbol_text(struct nk_context*, const char *selected, int, enum nk_symbol_type, struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_image(struct nk_context*, struct nk_image img,  struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_image_label(struct nk_context*, const char *selected, struct nk_image, struct nk_vec2 size);\nNK_API nk_bool nk_combo_begin_image_text(struct nk_context*,  const char *selected, int, struct nk_image, struct nk_vec2 size);\nNK_API nk_bool nk_combo_item_label(struct nk_context*, const char*, nk_flags alignment);\nNK_API nk_bool nk_combo_item_text(struct nk_context*, const char*,int, nk_flags alignment);\nNK_API nk_bool nk_combo_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);\nNK_API nk_bool nk_combo_item_image_text(struct nk_context*, struct nk_image, const char*, int,nk_flags alignment);\nNK_API nk_bool nk_combo_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);\nNK_API nk_bool nk_combo_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);\nNK_API void nk_combo_close(struct nk_context*);\nNK_API void nk_combo_end(struct nk_context*);\n/* =============================================================================\n *\n *                                  CONTEXTUAL\n *\n * ============================================================================= */\nNK_API nk_bool nk_contextual_begin(struct nk_context*, nk_flags, struct nk_vec2, struct nk_rect trigger_bounds);\nNK_API nk_bool nk_contextual_item_text(struct nk_context*, const char*, int,nk_flags align);\nNK_API nk_bool nk_contextual_item_label(struct nk_context*, const char*, nk_flags align);\nNK_API nk_bool nk_contextual_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);\nNK_API nk_bool nk_contextual_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment);\nNK_API nk_bool nk_contextual_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);\nNK_API nk_bool nk_contextual_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);\nNK_API void nk_contextual_close(struct nk_context*);\nNK_API void nk_contextual_end(struct nk_context*);\n/* =============================================================================\n *\n *                                  TOOLTIP\n *\n * ============================================================================= */\nNK_API void nk_tooltip(struct nk_context*, const char*);\nNK_API void nk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset);\n#ifdef NK_INCLUDE_STANDARD_VARARGS\nNK_API void nk_tooltipf(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(2);\nNK_API void nk_tooltipfv(struct nk_context*, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(2);\nNK_API void nk_tooltipf_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, ...) NK_PRINTF_VARARG_FUNC(4);\nNK_API void nk_tooltipfv_offset(struct nk_context*, enum nk_tooltip_pos, struct nk_vec2, NK_PRINTF_FORMAT_STRING const char*, va_list) NK_PRINTF_VALIST_FUNC(4);\n#endif\nNK_API nk_bool nk_tooltip_begin(struct nk_context*, float width);\nNK_API nk_bool nk_tooltip_begin_offset(struct nk_context*, float, enum nk_tooltip_pos, struct nk_vec2);\nNK_API void nk_tooltip_end(struct nk_context*);\n/* =============================================================================\n *\n *                                  MENU\n *\n * ============================================================================= */\nNK_API void nk_menubar_begin(struct nk_context*);\nNK_API void nk_menubar_end(struct nk_context*);\nNK_API nk_bool nk_menu_begin_text(struct nk_context*, const char* title, int title_len, nk_flags align, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_label(struct nk_context*, const char*, nk_flags align, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_image(struct nk_context*, const char*, struct nk_image, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_image_text(struct nk_context*, const char*, int,nk_flags align,struct nk_image, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_image_label(struct nk_context*, const char*, nk_flags align,struct nk_image, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_symbol(struct nk_context*, const char*, enum nk_symbol_type, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_symbol_text(struct nk_context*, const char*, int,nk_flags align,enum nk_symbol_type, struct nk_vec2 size);\nNK_API nk_bool nk_menu_begin_symbol_label(struct nk_context*, const char*, nk_flags align,enum nk_symbol_type, struct nk_vec2 size);\nNK_API nk_bool nk_menu_item_text(struct nk_context*, const char*, int,nk_flags align);\nNK_API nk_bool nk_menu_item_label(struct nk_context*, const char*, nk_flags alignment);\nNK_API nk_bool nk_menu_item_image_label(struct nk_context*, struct nk_image, const char*, nk_flags alignment);\nNK_API nk_bool nk_menu_item_image_text(struct nk_context*, struct nk_image, const char*, int len, nk_flags alignment);\nNK_API nk_bool nk_menu_item_symbol_text(struct nk_context*, enum nk_symbol_type, const char*, int, nk_flags alignment);\nNK_API nk_bool nk_menu_item_symbol_label(struct nk_context*, enum nk_symbol_type, const char*, nk_flags alignment);\nNK_API void nk_menu_close(struct nk_context*);\nNK_API void nk_menu_end(struct nk_context*);\n/* =============================================================================\n *\n *                                  STYLE\n *\n * ============================================================================= */\n\n#define NK_WIDGET_DISABLED_FACTOR 0.5f\n\nenum nk_style_colors {\n    NK_COLOR_TEXT,\n    NK_COLOR_WINDOW,\n    NK_COLOR_HEADER,\n    NK_COLOR_BORDER,\n    NK_COLOR_BUTTON,\n    NK_COLOR_BUTTON_HOVER,\n    NK_COLOR_BUTTON_ACTIVE,\n    NK_COLOR_TOGGLE,\n    NK_COLOR_TOGGLE_HOVER,\n    NK_COLOR_TOGGLE_CURSOR,\n    NK_COLOR_SELECT,\n    NK_COLOR_SELECT_ACTIVE,\n    NK_COLOR_SLIDER,\n    NK_COLOR_SLIDER_CURSOR,\n    NK_COLOR_SLIDER_CURSOR_HOVER,\n    NK_COLOR_SLIDER_CURSOR_ACTIVE,\n    NK_COLOR_PROPERTY,\n    NK_COLOR_EDIT,\n    NK_COLOR_EDIT_CURSOR,\n    NK_COLOR_COMBO,\n    NK_COLOR_CHART,\n    NK_COLOR_CHART_COLOR,\n    NK_COLOR_CHART_COLOR_HIGHLIGHT,\n    NK_COLOR_SCROLLBAR,\n    NK_COLOR_SCROLLBAR_CURSOR,\n    NK_COLOR_SCROLLBAR_CURSOR_HOVER,\n    NK_COLOR_SCROLLBAR_CURSOR_ACTIVE,\n    NK_COLOR_TAB_HEADER,\n    NK_COLOR_KNOB,\n    NK_COLOR_KNOB_CURSOR,\n    NK_COLOR_KNOB_CURSOR_HOVER,\n    NK_COLOR_KNOB_CURSOR_ACTIVE,\n    NK_COLOR_COUNT\n};\nenum nk_style_cursor {\n    NK_CURSOR_ARROW,\n    NK_CURSOR_TEXT,\n    NK_CURSOR_MOVE,\n    NK_CURSOR_RESIZE_VERTICAL,\n    NK_CURSOR_RESIZE_HORIZONTAL,\n    NK_CURSOR_RESIZE_TOP_LEFT_DOWN_RIGHT,\n    NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT,\n    NK_CURSOR_COUNT\n};\nNK_API void nk_style_default(struct nk_context*);\nNK_API void nk_style_from_table(struct nk_context*, const struct nk_color*);\nNK_API void nk_style_load_cursor(struct nk_context*, enum nk_style_cursor, const struct nk_cursor*);\nNK_API void nk_style_load_all_cursors(struct nk_context*, const struct nk_cursor*);\nNK_API const char* nk_style_get_color_by_name(enum nk_style_colors);\nNK_API void nk_style_set_font(struct nk_context*, const struct nk_user_font*);\nNK_API nk_bool nk_style_set_cursor(struct nk_context*, enum nk_style_cursor);\nNK_API void nk_style_show_cursor(struct nk_context*);\nNK_API void nk_style_hide_cursor(struct nk_context*);\n\nNK_API nk_bool nk_style_push_font(struct nk_context*, const struct nk_user_font*);\nNK_API nk_bool nk_style_push_float(struct nk_context*, float*, float);\nNK_API nk_bool nk_style_push_vec2(struct nk_context*, struct nk_vec2*, struct nk_vec2);\nNK_API nk_bool nk_style_push_style_item(struct nk_context*, struct nk_style_item*, struct nk_style_item);\nNK_API nk_bool nk_style_push_flags(struct nk_context*, nk_flags*, nk_flags);\nNK_API nk_bool nk_style_push_color(struct nk_context*, struct nk_color*, struct nk_color);\n\nNK_API nk_bool nk_style_pop_font(struct nk_context*);\nNK_API nk_bool nk_style_pop_float(struct nk_context*);\nNK_API nk_bool nk_style_pop_vec2(struct nk_context*);\nNK_API nk_bool nk_style_pop_style_item(struct nk_context*);\nNK_API nk_bool nk_style_pop_flags(struct nk_context*);\nNK_API nk_bool nk_style_pop_color(struct nk_context*);\n/* =============================================================================\n *\n *                                  COLOR\n *\n * ============================================================================= */\nNK_API struct nk_color nk_rgb(int r, int g, int b);\nNK_API struct nk_color nk_rgb_iv(const int *rgb);\nNK_API struct nk_color nk_rgb_bv(const nk_byte* rgb);\nNK_API struct nk_color nk_rgb_f(float r, float g, float b);\nNK_API struct nk_color nk_rgb_fv(const float *rgb);\nNK_API struct nk_color nk_rgb_cf(struct nk_colorf c);\nNK_API struct nk_color nk_rgb_hex(const char *rgb);\nNK_API struct nk_color nk_rgb_factor(struct nk_color col, float factor);\n\nNK_API struct nk_color nk_rgba(int r, int g, int b, int a);\nNK_API struct nk_color nk_rgba_u32(nk_uint);\nNK_API struct nk_color nk_rgba_iv(const int *rgba);\nNK_API struct nk_color nk_rgba_bv(const nk_byte *rgba);\nNK_API struct nk_color nk_rgba_f(float r, float g, float b, float a);\nNK_API struct nk_color nk_rgba_fv(const float *rgba);\nNK_API struct nk_color nk_rgba_cf(struct nk_colorf c);\nNK_API struct nk_color nk_rgba_hex(const char *rgb);\n\nNK_API struct nk_colorf nk_hsva_colorf(float h, float s, float v, float a);\nNK_API struct nk_colorf nk_hsva_colorfv(const float *c);\nNK_API void nk_colorf_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_colorf in);\nNK_API void nk_colorf_hsva_fv(float *hsva, struct nk_colorf in);\n\nNK_API struct nk_color nk_hsv(int h, int s, int v);\nNK_API struct nk_color nk_hsv_iv(const int *hsv);\nNK_API struct nk_color nk_hsv_bv(const nk_byte *hsv);\nNK_API struct nk_color nk_hsv_f(float h, float s, float v);\nNK_API struct nk_color nk_hsv_fv(const float *hsv);\n\nNK_API struct nk_color nk_hsva(int h, int s, int v, int a);\nNK_API struct nk_color nk_hsva_iv(const int *hsva);\nNK_API struct nk_color nk_hsva_bv(const nk_byte *hsva);\nNK_API struct nk_color nk_hsva_f(float h, float s, float v, float a);\nNK_API struct nk_color nk_hsva_fv(const float *hsva);\n\n/* color (conversion nuklear --> user) */\nNK_API void nk_color_f(float *r, float *g, float *b, float *a, struct nk_color);\nNK_API void nk_color_fv(float *rgba_out, struct nk_color);\nNK_API struct nk_colorf nk_color_cf(struct nk_color);\nNK_API void nk_color_d(double *r, double *g, double *b, double *a, struct nk_color);\nNK_API void nk_color_dv(double *rgba_out, struct nk_color);\n\nNK_API nk_uint nk_color_u32(struct nk_color);\nNK_API void nk_color_hex_rgba(char *output, struct nk_color);\nNK_API void nk_color_hex_rgb(char *output, struct nk_color);\n\nNK_API void nk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color);\nNK_API void nk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color);\nNK_API void nk_color_hsv_iv(int *hsv_out, struct nk_color);\nNK_API void nk_color_hsv_bv(nk_byte *hsv_out, struct nk_color);\nNK_API void nk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color);\nNK_API void nk_color_hsv_fv(float *hsv_out, struct nk_color);\n\nNK_API void nk_color_hsva_i(int *h, int *s, int *v, int *a, struct nk_color);\nNK_API void nk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color);\nNK_API void nk_color_hsva_iv(int *hsva_out, struct nk_color);\nNK_API void nk_color_hsva_bv(nk_byte *hsva_out, struct nk_color);\nNK_API void nk_color_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct nk_color);\nNK_API void nk_color_hsva_fv(float *hsva_out, struct nk_color);\n/* =============================================================================\n *\n *                                  IMAGE\n *\n * ============================================================================= */\nNK_API nk_handle nk_handle_ptr(void*);\nNK_API nk_handle nk_handle_id(int);\nNK_API struct nk_image nk_image_handle(nk_handle);\nNK_API struct nk_image nk_image_ptr(void*);\nNK_API struct nk_image nk_image_id(int);\nNK_API nk_bool nk_image_is_subimage(const struct nk_image* img);\nNK_API struct nk_image nk_subimage_ptr(void*, nk_ushort w, nk_ushort h, struct nk_rect sub_region);\nNK_API struct nk_image nk_subimage_id(int, nk_ushort w, nk_ushort h, struct nk_rect sub_region);\nNK_API struct nk_image nk_subimage_handle(nk_handle, nk_ushort w, nk_ushort h, struct nk_rect sub_region);\n/* =============================================================================\n *\n *                                  9-SLICE\n *\n * ============================================================================= */\nNK_API struct nk_nine_slice nk_nine_slice_handle(nk_handle, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);\nNK_API struct nk_nine_slice nk_nine_slice_ptr(void*, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);\nNK_API struct nk_nine_slice nk_nine_slice_id(int, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);\nNK_API int nk_nine_slice_is_sub9slice(const struct nk_nine_slice* img);\nNK_API struct nk_nine_slice nk_sub9slice_ptr(void*, nk_ushort w, nk_ushort h, struct nk_rect sub_region, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);\nNK_API struct nk_nine_slice nk_sub9slice_id(int, nk_ushort w, nk_ushort h, struct nk_rect sub_region, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);\nNK_API struct nk_nine_slice nk_sub9slice_handle(nk_handle, nk_ushort w, nk_ushort h, struct nk_rect sub_region, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b);\n/* =============================================================================\n *\n *                                  MATH\n *\n * ============================================================================= */\nNK_API nk_hash nk_murmur_hash(const void *key, int len, nk_hash seed);\nNK_API void nk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r, float pad_x, float pad_y, enum nk_heading);\n\nNK_API struct nk_vec2 nk_vec2(float x, float y);\nNK_API struct nk_vec2 nk_vec2i(int x, int y);\nNK_API struct nk_vec2 nk_vec2v(const float *xy);\nNK_API struct nk_vec2 nk_vec2iv(const int *xy);\n\nNK_API struct nk_rect nk_get_null_rect(void);\nNK_API struct nk_rect nk_rect(float x, float y, float w, float h);\nNK_API struct nk_rect nk_recti(int x, int y, int w, int h);\nNK_API struct nk_rect nk_recta(struct nk_vec2 pos, struct nk_vec2 size);\nNK_API struct nk_rect nk_rectv(const float *xywh);\nNK_API struct nk_rect nk_rectiv(const int *xywh);\nNK_API struct nk_vec2 nk_rect_pos(struct nk_rect);\nNK_API struct nk_vec2 nk_rect_size(struct nk_rect);\n/* =============================================================================\n *\n *                                  STRING\n *\n * ============================================================================= */\nNK_API int nk_strlen(const char *str);\nNK_API int nk_stricmp(const char *s1, const char *s2);\nNK_API int nk_stricmpn(const char *s1, const char *s2, int n);\nNK_API int nk_strtoi(const char *str, char **endptr);\nNK_API float nk_strtof(const char *str, char **endptr);\n#ifndef NK_STRTOD\n#define NK_STRTOD nk_strtod\n#define NK_STRTOD_NEEDED\nNK_API double nk_strtod(const char *str, char **endptr);\n#endif\nNK_API int nk_strfilter(const char *text, const char *regexp);\nNK_API int nk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score);\nNK_API int nk_strmatch_fuzzy_text(const char *txt, int txt_len, const char *pattern, int *out_score);\n/* =============================================================================\n *\n *                                  UTF-8\n *\n * ============================================================================= */\nNK_API int nk_utf_decode(const char*, nk_rune*, int);\nNK_API int nk_utf_encode(nk_rune, char*, int);\nNK_API int nk_utf_len(const char*, int byte_len);\nNK_API const char* nk_utf_at(const char *buffer, int length, int index, nk_rune *unicode, int *len);\n/* ===============================================================\n *\n *                          FONT\n *\n * ===============================================================*/\n/**\n * \\page Font\n * Font handling in this library was designed to be quite customizable and lets\n * you decide what you want to use and what you want to provide. There are three\n * different ways to use the font atlas. The first two will use your font\n * handling scheme and only requires essential data to run nuklear. The next\n * slightly more advanced features is font handling with vertex buffer output.\n * Finally the most complex API wise is using nuklear's font baking API.\n *\n * # Using your own implementation without vertex buffer output\n *\n * So first up the easiest way to do font handling is by just providing a\n * `nk_user_font` struct which only requires the height in pixel of the used\n * font and a callback to calculate the width of a string. This way of handling\n * fonts is best fitted for using the normal draw shape command API where you\n * do all the text drawing yourself and the library does not require any kind\n * of deeper knowledge about which font handling mechanism you use.\n * IMPORTANT: the `nk_user_font` pointer provided to nuklear has to persist\n * over the complete life time! I know this sucks but it is currently the only\n * way to switch between fonts.\n *\n * ```c\n *     float your_text_width_calculation(nk_handle handle, float height, const char *text, int len)\n *     {\n *         your_font_type *type = handle.ptr;\n *         float text_width = ...;\n *         return text_width;\n *     }\n *\n *     struct nk_user_font font;\n *     font.userdata.ptr = &your_font_class_or_struct;\n *     font.height = your_font_height;\n *     font.width = your_text_width_calculation;\n *\n *     struct nk_context ctx;\n *     nk_init_default(&ctx, &font);\n * ```\n * # Using your own implementation with vertex buffer output\n *\n * While the first approach works fine if you don't want to use the optional\n * vertex buffer output it is not enough if you do. To get font handling working\n * for these cases you have to provide two additional parameters inside the\n * `nk_user_font`. First a texture atlas handle used to draw text as subimages\n * of a bigger font atlas texture and a callback to query a character's glyph\n * information (offset, size, ...). So it is still possible to provide your own\n * font and use the vertex buffer output.\n *\n * ```c\n *     float your_text_width_calculation(nk_handle handle, float height, const char *text, int len)\n *     {\n *         your_font_type *type = handle.ptr;\n *         float text_width = ...;\n *         return text_width;\n *     }\n *     void query_your_font_glyph(nk_handle handle, float font_height, struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint)\n *     {\n *         your_font_type *type = handle.ptr;\n *         glyph.width = ...;\n *         glyph.height = ...;\n *         glyph.xadvance = ...;\n *         glyph.uv[0].x = ...;\n *         glyph.uv[0].y = ...;\n *         glyph.uv[1].x = ...;\n *         glyph.uv[1].y = ...;\n *         glyph.offset.x = ...;\n *         glyph.offset.y = ...;\n *     }\n *\n *     struct nk_user_font font;\n *     font.userdata.ptr = &your_font_class_or_struct;\n *     font.height = your_font_height;\n *     font.width = your_text_width_calculation;\n *     font.query = query_your_font_glyph;\n *     font.texture.id = your_font_texture;\n *\n *     struct nk_context ctx;\n *     nk_init_default(&ctx, &font);\n * ```\n *\n * # Nuklear font baker\n *\n * The final approach if you do not have a font handling functionality or don't\n * want to use it in this library is by using the optional font baker.\n * The font baker APIs can be used to create a font plus font atlas texture\n * and can be used with or without the vertex buffer output.\n *\n * It still uses the `nk_user_font` struct and the two different approaches\n * previously stated still work. The font baker is not located inside\n * `nk_context` like all other systems since it can be understood as more of\n * an extension to nuklear and does not really depend on any `nk_context` state.\n *\n * Font baker need to be initialized first by one of the nk_font_atlas_init_xxx\n * functions. If you don't care about memory just call the default version\n * `nk_font_atlas_init_default` which will allocate all memory from the standard library.\n * If you want to control memory allocation but you don't care if the allocated\n * memory is temporary and therefore can be freed directly after the baking process\n * is over or permanent you can call `nk_font_atlas_init`.\n *\n * After successfully initializing the font baker you can add Truetype(.ttf) fonts from\n * different sources like memory or from file by calling one of the `nk_font_atlas_add_xxx`.\n * functions. Adding font will permanently store each font, font config and ttf memory block(!)\n * inside the font atlas and allows to reuse the font atlas. If you don't want to reuse\n * the font baker by for example adding additional fonts you can call\n * `nk_font_atlas_cleanup` after the baking process is over (after calling nk_font_atlas_end).\n *\n * As soon as you added all fonts you wanted you can now start the baking process\n * for every selected glyph to image by calling `nk_font_atlas_bake`.\n * The baking process returns image memory, width and height which can be used to\n * either create your own image object or upload it to any graphics library.\n * No matter which case you finally have to call `nk_font_atlas_end` which\n * will free all temporary memory including the font atlas image so make sure\n * you created our texture beforehand. `nk_font_atlas_end` requires a handle\n * to your font texture or object and optionally fills a `struct nk_draw_null_texture`\n * which can be used for the optional vertex output. If you don't want it just\n * set the argument to `NULL`.\n *\n * At this point you are done and if you don't want to reuse the font atlas you\n * can call `nk_font_atlas_cleanup` to free all truetype blobs and configuration\n * memory. Finally if you don't use the font atlas and any of it's fonts anymore\n * you need to call `nk_font_atlas_clear` to free all memory still being used.\n *\n * ```c\n *     struct nk_font_atlas atlas;\n *     nk_font_atlas_init_default(&atlas);\n *     nk_font_atlas_begin(&atlas);\n *     nk_font *font = nk_font_atlas_add_from_file(&atlas, \"Path/To/Your/TTF_Font.ttf\", 13, 0);\n *     nk_font *font2 = nk_font_atlas_add_from_file(&atlas, \"Path/To/Your/TTF_Font2.ttf\", 16, 0);\n *     const void* img = nk_font_atlas_bake(&atlas, &img_width, &img_height, NK_FONT_ATLAS_RGBA32);\n *     nk_font_atlas_end(&atlas, nk_handle_id(texture), 0);\n *\n *     struct nk_context ctx;\n *     nk_init_default(&ctx, &font->handle);\n *     while (1) {\n *\n *     }\n *     nk_font_atlas_clear(&atlas);\n * ```\n * The font baker API is probably the most complex API inside this library and\n * I would suggest reading some of my examples `example/` to get a grip on how\n * to use the font atlas. There are a number of details I left out. For example\n * how to merge fonts, configure a font with `nk_font_config` to use other languages,\n * use another texture coordinate format and a lot more:\n *\n * ```c\n *     struct nk_font_config cfg = nk_font_config(font_pixel_height);\n *     cfg.merge_mode = nk_false or nk_true;\n *     cfg.range = nk_font_korean_glyph_ranges();\n *     cfg.coord_type = NK_COORD_PIXEL;\n *     nk_font *font = nk_font_atlas_add_from_file(&atlas, \"Path/To/Your/TTF_Font.ttf\", 13, &cfg);\n * ```\n */\n\nstruct nk_user_font_glyph;\ntypedef float(*nk_text_width_f)(nk_handle, float h, const char*, int len);\ntypedef void(*nk_query_font_glyph_f)(nk_handle handle, float font_height,\n                                    struct nk_user_font_glyph *glyph,\n                                    nk_rune codepoint, nk_rune next_codepoint);\n\n#if defined(NK_INCLUDE_VERTEX_BUFFER_OUTPUT) || defined(NK_INCLUDE_SOFTWARE_FONT)\nstruct nk_user_font_glyph {\n    struct nk_vec2 uv[2];  /**!< texture coordinates */\n    struct nk_vec2 offset; /**!< offset between top left and glyph */\n    float width, height;   /**!< size of the glyph  */\n    float xadvance;        /**!< offset to the next glyph */\n};\n#endif\n\nstruct nk_user_font {\n    nk_handle userdata;    /**!< user provided font handle */\n    float height;          /**!< max height of the font */\n    nk_text_width_f width; /**!< font string width in pixel callback */\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n    nk_query_font_glyph_f query; /**!< font glyph callback to query drawing info */\n    nk_handle texture;           /**!< texture handle to the used font atlas or texture */\n#endif\n};\n\n#ifdef NK_INCLUDE_FONT_BAKING\nenum nk_font_coord_type {\n    NK_COORD_UV,   /**!< texture coordinates inside font glyphs are clamped between 0-1 */\n    NK_COORD_PIXEL /**!< texture coordinates inside font glyphs are in absolute pixel */\n};\n\nstruct nk_font;\nstruct nk_baked_font {\n    float height;          /**!< height of the font  */\n    float ascent;          /**!< font glyphs ascent and descent  */\n    float descent;         /**!< font glyphs ascent and descent  */\n    nk_rune glyph_offset;  /**!< glyph array offset inside the font glyph baking output array  */\n    nk_rune glyph_count;   /**!< number of glyphs of this font inside the glyph baking array output */\n    const nk_rune *ranges; /**!< font codepoint ranges as pairs of (from/to) and 0 as last element */\n};\n\nstruct nk_font_config {\n    struct nk_font_config *next; /**!< NOTE: only used internally */\n    void *ttf_blob;              /**!< pointer to loaded TTF file memory block.  * \\note not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */\n    nk_size ttf_size;            /**!< size of the loaded TTF file memory block * \\note not needed for nk_font_atlas_add_from_memory and nk_font_atlas_add_from_file. */\n\n    unsigned char ttf_data_owned_by_atlas;    /**!< used inside font atlas: default to: 0*/\n    unsigned char merge_mode;                 /**!< merges this font into the last font */\n    unsigned char pixel_snap;                 /**!< align every character to pixel boundary (if true set oversample (1,1)) */\n    unsigned char oversample_v, oversample_h; /**!< rasterize at high quality for sub-pixel position */\n    unsigned char padding[3];\n\n    float size;                         /**!< baked pixel height of the font */\n    enum nk_font_coord_type coord_type; /**!< texture coordinate format with either pixel or UV coordinates */\n    struct nk_vec2 spacing;             /**!< extra pixel spacing between glyphs  */\n    const nk_rune *range;               /**!< list of unicode ranges (2 values per range, zero terminated) */\n    struct nk_baked_font *font;         /**!< font to setup in the baking process: NOTE: not needed for font atlas */\n    nk_rune fallback_glyph;             /**!< fallback glyph to use if a given rune is not found */\n    struct nk_font_config *n;\n    struct nk_font_config *p;\n};\n\nstruct nk_font_glyph {\n    nk_rune codepoint;\n    float xadvance;\n    float x0, y0, x1, y1, w, h;\n    float u0, v0, u1, v1;\n};\n\nstruct nk_font {\n    struct nk_font *next;\n    struct nk_user_font handle;\n    struct nk_baked_font info;\n    float scale;\n    struct nk_font_glyph *glyphs;\n    const struct nk_font_glyph *fallback;\n    nk_rune fallback_codepoint;\n    nk_handle texture;\n    struct nk_font_config *config;\n};\n\nenum nk_font_atlas_format {\n    NK_FONT_ATLAS_ALPHA8,\n    NK_FONT_ATLAS_RGBA32\n};\n\nstruct nk_font_atlas {\n    void *pixel;\n    int tex_width;\n    int tex_height;\n\n    struct nk_allocator permanent;\n    struct nk_allocator temporary;\n\n    struct nk_recti custom;\n    struct nk_cursor cursors[NK_CURSOR_COUNT];\n\n    int glyph_count;\n    struct nk_font_glyph *glyphs;\n    struct nk_font *default_font;\n    struct nk_font *fonts;\n    struct nk_font_config *config;\n    int font_num;\n};\n\n/** some language glyph codepoint ranges */\nNK_API const nk_rune *nk_font_default_glyph_ranges(void);\nNK_API const nk_rune *nk_font_chinese_glyph_ranges(void);\nNK_API const nk_rune *nk_font_cyrillic_glyph_ranges(void);\nNK_API const nk_rune *nk_font_korean_glyph_ranges(void);\n\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void nk_font_atlas_init_default(struct nk_font_atlas*);\n#endif\nNK_API void nk_font_atlas_init(struct nk_font_atlas*, const struct nk_allocator*);\nNK_API void nk_font_atlas_init_custom(struct nk_font_atlas*, const struct nk_allocator *persistent, const struct nk_allocator *transient);\nNK_API void nk_font_atlas_begin(struct nk_font_atlas*);\nNK_API struct nk_font_config nk_font_config(float pixel_height);\nNK_API struct nk_font *nk_font_atlas_add(struct nk_font_atlas*, const struct nk_font_config*);\n#ifdef NK_INCLUDE_DEFAULT_FONT\nNK_API struct nk_font* nk_font_atlas_add_default(struct nk_font_atlas*, float height, const struct nk_font_config*);\n#endif\nNK_API struct nk_font* nk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory, nk_size size, float height, const struct nk_font_config *config);\n#ifdef NK_INCLUDE_STANDARD_IO\nNK_API struct nk_font* nk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path, float height, const struct nk_font_config*);\n#endif\nNK_API struct nk_font *nk_font_atlas_add_compressed(struct nk_font_atlas*, void *memory, nk_size size, float height, const struct nk_font_config*);\nNK_API struct nk_font* nk_font_atlas_add_compressed_base85(struct nk_font_atlas*, const char *data, float height, const struct nk_font_config *config);\nNK_API const void* nk_font_atlas_bake(struct nk_font_atlas*, int *width, int *height, enum nk_font_atlas_format);\nNK_API void nk_font_atlas_end(struct nk_font_atlas*, nk_handle tex, struct nk_draw_null_texture*);\nNK_API const struct nk_font_glyph* nk_font_find_glyph(const struct nk_font*, nk_rune unicode);\nNK_API void nk_font_atlas_cleanup(struct nk_font_atlas *atlas);\nNK_API void nk_font_atlas_clear(struct nk_font_atlas*);\n\n#endif\n\n/* ==============================================================\n *\n *                          MEMORY BUFFER\n *\n * ===============================================================*/\n/**\n * \\page Memory Buffer\n * A basic (double)-buffer with linear allocation and resetting as only\n * freeing policy. The buffer's main purpose is to control all memory management\n * inside the GUI toolkit and still leave memory control as much as possible in\n * the hand of the user while also making sure the library is easy to use if\n * not as much control is needed.\n * In general all memory inside this library can be provided from the user in\n * three different ways.\n *\n * The first way and the one providing most control is by just passing a fixed\n * size memory block. In this case all control lies in the hand of the user\n * since he can exactly control where the memory comes from and how much memory\n * the library should consume. Of course using the fixed size API removes the\n * ability to automatically resize a buffer if not enough memory is provided so\n * you have to take over the resizing. While being a fixed sized buffer sounds\n * quite limiting, it is very effective in this library since the actual memory\n * consumption is quite stable and has a fixed upper bound for a lot of cases.\n *\n * If you don't want to think about how much memory the library should allocate\n * at all time or have a very dynamic UI with unpredictable memory consumption\n * habits but still want control over memory allocation you can use the dynamic\n * allocator based API. The allocator consists of two callbacks for allocating\n * and freeing memory and optional userdata so you can plugin your own allocator.\n *\n * The final and easiest way can be used by defining\n * NK_INCLUDE_DEFAULT_ALLOCATOR which uses the standard library memory\n * allocation functions malloc and free and takes over complete control over\n * memory in this library.\n */\n\nstruct nk_memory_status {\n    void *memory;\n    unsigned int type;\n    nk_size size;\n    nk_size allocated;\n    nk_size needed;\n    nk_size calls;\n};\n\nenum nk_allocation_type {\n    NK_BUFFER_FIXED,\n    NK_BUFFER_DYNAMIC\n};\n\nenum nk_buffer_allocation_type {\n    NK_BUFFER_FRONT,\n    NK_BUFFER_BACK,\n    NK_BUFFER_MAX\n};\n\nstruct nk_buffer_marker {\n    nk_bool active;\n    nk_size offset;\n};\n\nstruct nk_memory {void *ptr;nk_size size;};\nstruct nk_buffer {\n    struct nk_buffer_marker marker[NK_BUFFER_MAX]; /**!< buffer marker to free a buffer to a certain offset */\n    struct nk_allocator pool;     /**!< allocator callback for dynamic buffers */\n    enum nk_allocation_type type; /**!< memory management type */\n    struct nk_memory memory;      /**!< memory and size of the current memory block */\n    float grow_factor;            /**!< growing factor for dynamic memory management */\n    nk_size allocated;            /**!< total amount of memory allocated */\n    nk_size needed;               /**!< totally consumed memory given that enough memory is present */\n    nk_size calls;                /**!< number of allocation calls */\n    nk_size size;                 /**!< current size of the buffer */\n};\n\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void nk_buffer_init_default(struct nk_buffer*);\n#endif\nNK_API void nk_buffer_init(struct nk_buffer*, const struct nk_allocator*, nk_size size);\nNK_API void nk_buffer_init_fixed(struct nk_buffer*, void *memory, nk_size size);\nNK_API void nk_buffer_info(struct nk_memory_status*, const struct nk_buffer*);\nNK_API void nk_buffer_push(struct nk_buffer*, enum nk_buffer_allocation_type type, const void *memory, nk_size size, nk_size align);\nNK_API void nk_buffer_mark(struct nk_buffer*, enum nk_buffer_allocation_type type);\nNK_API void nk_buffer_reset(struct nk_buffer*, enum nk_buffer_allocation_type type);\nNK_API void nk_buffer_clear(struct nk_buffer*);\nNK_API void nk_buffer_free(struct nk_buffer*);\nNK_API void *nk_buffer_memory(struct nk_buffer*);\nNK_API const void *nk_buffer_memory_const(const struct nk_buffer*);\nNK_API nk_size nk_buffer_total(const struct nk_buffer*);\n\n/* ==============================================================\n *\n *                          STRING\n *\n * ===============================================================*/\n/**  Basic string buffer which is only used in context with the text editor\n *  to manage and manipulate dynamic or fixed size string content. This is _NOT_\n *  the default string handling method. The only instance you should have any contact\n *  with this API is if you interact with an `nk_text_edit` object inside one of the\n *  copy and paste functions and even there only for more advanced cases. */\nstruct nk_str {\n    struct nk_buffer buffer;\n    int len; /**!< in codepoints/runes/glyphs */\n};\n\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void nk_str_init_default(struct nk_str*);\n#endif\nNK_API void nk_str_init(struct nk_str*, const struct nk_allocator*, nk_size size);\nNK_API void nk_str_init_fixed(struct nk_str*, void *memory, nk_size size);\nNK_API void nk_str_clear(struct nk_str*);\nNK_API void nk_str_free(struct nk_str*);\n\nNK_API int nk_str_append_text_char(struct nk_str*, const char*, int);\nNK_API int nk_str_append_str_char(struct nk_str*, const char*);\nNK_API int nk_str_append_text_utf8(struct nk_str*, const char*, int);\nNK_API int nk_str_append_str_utf8(struct nk_str*, const char*);\nNK_API int nk_str_append_text_runes(struct nk_str*, const nk_rune*, int);\nNK_API int nk_str_append_str_runes(struct nk_str*, const nk_rune*);\n\nNK_API int nk_str_insert_at_char(struct nk_str*, int pos, const char*, int);\nNK_API int nk_str_insert_at_rune(struct nk_str*, int pos, const char*, int);\n\nNK_API int nk_str_insert_text_char(struct nk_str*, int pos, const char*, int);\nNK_API int nk_str_insert_str_char(struct nk_str*, int pos, const char*);\nNK_API int nk_str_insert_text_utf8(struct nk_str*, int pos, const char*, int);\nNK_API int nk_str_insert_str_utf8(struct nk_str*, int pos, const char*);\nNK_API int nk_str_insert_text_runes(struct nk_str*, int pos, const nk_rune*, int);\nNK_API int nk_str_insert_str_runes(struct nk_str*, int pos, const nk_rune*);\n\nNK_API void nk_str_remove_chars(struct nk_str*, int len);\nNK_API void nk_str_remove_runes(struct nk_str *str, int len);\nNK_API void nk_str_delete_chars(struct nk_str*, int pos, int len);\nNK_API void nk_str_delete_runes(struct nk_str*, int pos, int len);\n\nNK_API char *nk_str_at_char(struct nk_str*, int pos);\nNK_API char *nk_str_at_rune(struct nk_str*, int pos, nk_rune *unicode, int *len);\nNK_API nk_rune nk_str_rune_at(const struct nk_str*, int pos);\nNK_API const char *nk_str_at_char_const(const struct nk_str*, int pos);\nNK_API const char *nk_str_at_const(const struct nk_str*, int pos, nk_rune *unicode, int *len);\n\nNK_API char *nk_str_get(struct nk_str*);\nNK_API const char *nk_str_get_const(const struct nk_str*);\nNK_API int nk_str_len(const struct nk_str*);\nNK_API int nk_str_len_char(const struct nk_str*);\n\n/* ===============================================================\n *\n *                      TEXT EDITOR\n *\n * ===============================================================*/\n/**\n * \\page Text Editor\n * Editing text in this library is handled by either `nk_edit_string` or\n * `nk_edit_buffer`. But like almost everything in this library there are multiple\n * ways of doing it and a balance between control and ease of use with memory\n * as well as functionality controlled by flags.\n *\n * This library generally allows three different levels of memory control:\n * First of is the most basic way of just providing a simple char array with\n * string length. This method is probably the easiest way of handling simple\n * user text input. Main upside is complete control over memory while the biggest\n * downside in comparison with the other two approaches is missing undo/redo.\n *\n * For UIs that require undo/redo the second way was created. It is based on\n * a fixed size nk_text_edit struct, which has an internal undo/redo stack.\n * This is mainly useful if you want something more like a text editor but don't want\n * to have a dynamically growing buffer.\n *\n * The final way is using a dynamically growing nk_text_edit struct, which\n * has both a default version if you don't care where memory comes from and an\n * allocator version if you do. While the text editor is quite powerful for its\n * complexity I would not recommend editing gigabytes of data with it.\n * It is rather designed for uses cases which make sense for a GUI library not for\n * an full blown text editor.\n */\n\n#ifndef NK_TEXTEDIT_UNDOSTATECOUNT\n#define NK_TEXTEDIT_UNDOSTATECOUNT     99\n#endif\n\n#ifndef NK_TEXTEDIT_UNDOCHARCOUNT\n#define NK_TEXTEDIT_UNDOCHARCOUNT      999\n#endif\n\nstruct nk_text_edit;\nstruct nk_clipboard {\n    nk_handle userdata;\n    nk_plugin_paste paste;\n    nk_plugin_copy copy;\n};\n\nstruct nk_text_undo_record {\n   int where;\n   short insert_length;\n   short delete_length;\n   short char_storage;\n};\n\nstruct nk_text_undo_state {\n   struct nk_text_undo_record undo_rec[NK_TEXTEDIT_UNDOSTATECOUNT];\n   nk_rune undo_char[NK_TEXTEDIT_UNDOCHARCOUNT];\n   short undo_point;\n   short redo_point;\n   short undo_char_point;\n   short redo_char_point;\n};\n\nenum nk_text_edit_type {\n    NK_TEXT_EDIT_SINGLE_LINE,\n    NK_TEXT_EDIT_MULTI_LINE\n};\n\nenum nk_text_edit_mode {\n    NK_TEXT_EDIT_MODE_VIEW,\n    NK_TEXT_EDIT_MODE_INSERT,\n    NK_TEXT_EDIT_MODE_REPLACE\n};\n\nstruct nk_text_edit {\n    struct nk_clipboard clip;\n    struct nk_str string;\n    nk_plugin_filter filter;\n    struct nk_vec2 scrollbar;\n\n    int cursor;\n    int select_start;\n    int select_end;\n    unsigned char mode;\n    unsigned char cursor_at_end_of_line;\n    unsigned char initialized;\n    unsigned char has_preferred_x;\n    unsigned char single_line;\n    unsigned char active;\n    unsigned char padding1;\n    float preferred_x;\n    struct nk_text_undo_state undo;\n};\n\n/** filter function */\nNK_API nk_bool nk_filter_default(const struct nk_text_edit*, nk_rune unicode);\nNK_API nk_bool nk_filter_ascii(const struct nk_text_edit*, nk_rune unicode);\nNK_API nk_bool nk_filter_float(const struct nk_text_edit*, nk_rune unicode);\nNK_API nk_bool nk_filter_decimal(const struct nk_text_edit*, nk_rune unicode);\nNK_API nk_bool nk_filter_hex(const struct nk_text_edit*, nk_rune unicode);\nNK_API nk_bool nk_filter_oct(const struct nk_text_edit*, nk_rune unicode);\nNK_API nk_bool nk_filter_binary(const struct nk_text_edit*, nk_rune unicode);\n\n/** text editor */\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void nk_textedit_init_default(struct nk_text_edit*);\n#endif\nNK_API void nk_textedit_init(struct nk_text_edit*, const struct nk_allocator*, nk_size size);\nNK_API void nk_textedit_init_fixed(struct nk_text_edit*, void *memory, nk_size size);\nNK_API void nk_textedit_free(struct nk_text_edit*);\nNK_API void nk_textedit_text(struct nk_text_edit*, const char*, int total_len);\nNK_API void nk_textedit_delete(struct nk_text_edit*, int where, int len);\nNK_API void nk_textedit_delete_selection(struct nk_text_edit*);\nNK_API void nk_textedit_select_all(struct nk_text_edit*);\nNK_API nk_bool nk_textedit_cut(struct nk_text_edit*);\nNK_API nk_bool nk_textedit_paste(struct nk_text_edit*, char const*, int len);\nNK_API void nk_textedit_undo(struct nk_text_edit*);\nNK_API void nk_textedit_redo(struct nk_text_edit*);\n\n/* ===============================================================\n *\n *                          DRAWING\n *\n * ===============================================================*/\n/**\n * \\page Drawing\n * This library was designed to be render backend agnostic so it does\n * not draw anything to screen. Instead all drawn shapes, widgets\n * are made of, are buffered into memory and make up a command queue.\n * Each frame therefore fills the command buffer with draw commands\n * that then need to be executed by the user and his own render backend.\n * After that the command buffer needs to be cleared and a new frame can be\n * started. It is probably important to note that the command buffer is the main\n * drawing API and the optional vertex buffer API only takes this format and\n * converts it into a hardware accessible format.\n *\n * To use the command queue to draw your own widgets you can access the\n * command buffer of each window by calling `nk_window_get_canvas` after\n * previously having called `nk_begin`:\n *\n * ```c\n *     void draw_red_rectangle_widget(struct nk_context *ctx)\n *     {\n *         struct nk_command_buffer *canvas;\n *         struct nk_input *input = &ctx->input;\n *         canvas = nk_window_get_canvas(ctx);\n *\n *         struct nk_rect space;\n *         enum nk_widget_layout_states state;\n *         state = nk_widget(&space, ctx);\n *         if (!state) return;\n *\n *         if (state != NK_WIDGET_ROM)\n *             update_your_widget_by_user_input(...);\n *         nk_fill_rect(canvas, space, 0, nk_rgb(255,0,0));\n *     }\n *\n *     if (nk_begin(...)) {\n *         nk_layout_row_dynamic(ctx, 25, 1);\n *         draw_red_rectangle_widget(ctx);\n *     }\n *     nk_end(..)\n *\n * ```\n * Important to know if you want to create your own widgets is the `nk_widget`\n * call. It allocates space on the panel reserved for this widget to be used,\n * but also returns the state of the widget space. If your widget is not seen and does\n * not have to be updated it is '0' and you can just return. If it only has\n * to be drawn the state will be `NK_WIDGET_ROM` otherwise you can do both\n * update and draw your widget. The reason for separating is to only draw and\n * update what is actually necessary which is crucial for performance.\n */\n\nenum nk_command_type {\n    NK_COMMAND_NOP,\n    NK_COMMAND_SCISSOR,\n    NK_COMMAND_LINE,\n    NK_COMMAND_CURVE,\n    NK_COMMAND_RECT,\n    NK_COMMAND_RECT_FILLED,\n    NK_COMMAND_RECT_MULTI_COLOR,\n    NK_COMMAND_CIRCLE,\n    NK_COMMAND_CIRCLE_FILLED,\n    NK_COMMAND_ARC,\n    NK_COMMAND_ARC_FILLED,\n    NK_COMMAND_TRIANGLE,\n    NK_COMMAND_TRIANGLE_FILLED,\n    NK_COMMAND_POLYGON,\n    NK_COMMAND_POLYGON_FILLED,\n    NK_COMMAND_POLYLINE,\n    NK_COMMAND_TEXT,\n    NK_COMMAND_IMAGE,\n    NK_COMMAND_CUSTOM\n};\n\n /** command base and header of every command inside the buffer */\nstruct nk_command {\n    enum nk_command_type type;\n    nk_size next;\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    nk_handle userdata;\n#endif\n};\n\nstruct nk_command_scissor {\n    struct nk_command header;\n    short x, y;\n    unsigned short w, h;\n};\n\nstruct nk_command_line {\n    struct nk_command header;\n    unsigned short line_thickness;\n    struct nk_vec2i begin;\n    struct nk_vec2i end;\n    struct nk_color color;\n};\n\nstruct nk_command_curve {\n    struct nk_command header;\n    unsigned short line_thickness;\n    struct nk_vec2i begin;\n    struct nk_vec2i end;\n    struct nk_vec2i ctrl[2];\n    struct nk_color color;\n};\n\nstruct nk_command_rect {\n    struct nk_command header;\n    unsigned short rounding;\n    unsigned short line_thickness;\n    short x, y;\n    unsigned short w, h;\n    struct nk_color color;\n};\n\nstruct nk_command_rect_filled {\n    struct nk_command header;\n    unsigned short rounding;\n    short x, y;\n    unsigned short w, h;\n    struct nk_color color;\n};\n\nstruct nk_command_rect_multi_color {\n    struct nk_command header;\n    short x, y;\n    unsigned short w, h;\n    struct nk_color left;\n    struct nk_color top;\n    struct nk_color bottom;\n    struct nk_color right;\n};\n\nstruct nk_command_triangle {\n    struct nk_command header;\n    unsigned short line_thickness;\n    struct nk_vec2i a;\n    struct nk_vec2i b;\n    struct nk_vec2i c;\n    struct nk_color color;\n};\n\nstruct nk_command_triangle_filled {\n    struct nk_command header;\n    struct nk_vec2i a;\n    struct nk_vec2i b;\n    struct nk_vec2i c;\n    struct nk_color color;\n};\n\nstruct nk_command_circle {\n    struct nk_command header;\n    short x, y;\n    unsigned short line_thickness;\n    unsigned short w, h;\n    struct nk_color color;\n};\n\nstruct nk_command_circle_filled {\n    struct nk_command header;\n    short x, y;\n    unsigned short w, h;\n    struct nk_color color;\n};\n\nstruct nk_command_arc {\n    struct nk_command header;\n    short cx, cy;\n    unsigned short r;\n    unsigned short line_thickness;\n    float a[2];\n    struct nk_color color;\n};\n\nstruct nk_command_arc_filled {\n    struct nk_command header;\n    short cx, cy;\n    unsigned short r;\n    float a[2];\n    struct nk_color color;\n};\n\nstruct nk_command_polygon {\n    struct nk_command header;\n    struct nk_color color;\n    unsigned short line_thickness;\n    unsigned short point_count;\n    struct nk_vec2i points[1];\n};\n\nstruct nk_command_polygon_filled {\n    struct nk_command header;\n    struct nk_color color;\n    unsigned short point_count;\n    struct nk_vec2i points[1];\n};\n\nstruct nk_command_polyline {\n    struct nk_command header;\n    struct nk_color color;\n    unsigned short line_thickness;\n    unsigned short point_count;\n    struct nk_vec2i points[1];\n};\n\nstruct nk_command_image {\n    struct nk_command header;\n    short x, y;\n    unsigned short w, h;\n    struct nk_image img;\n    struct nk_color col;\n};\n\ntypedef void (*nk_command_custom_callback)(void *canvas, short x,short y,\n    unsigned short w, unsigned short h, nk_handle callback_data);\nstruct nk_command_custom {\n    struct nk_command header;\n    short x, y;\n    unsigned short w, h;\n    nk_handle callback_data;\n    nk_command_custom_callback callback;\n};\n\nstruct nk_command_text {\n    struct nk_command header;\n    const struct nk_user_font *font;\n    struct nk_color background;\n    struct nk_color foreground;\n    short x, y;\n    unsigned short w, h;\n    float height;\n    int length;\n    char string[2];\n};\n\nenum nk_command_clipping {\n    NK_CLIPPING_OFF = nk_false,\n    NK_CLIPPING_ON = nk_true\n};\n\nstruct nk_command_buffer {\n    struct nk_buffer *base;\n    struct nk_rect clip;\n    int use_clipping;\n    nk_handle userdata;\n    nk_size begin, end, last;\n};\n\n/** shape outlines */\nNK_API void nk_stroke_line(struct nk_command_buffer *b, float x0, float y0, float x1, float y1, float line_thickness, struct nk_color);\nNK_API void nk_stroke_curve(struct nk_command_buffer*, float, float, float, float, float, float, float, float, float line_thickness, struct nk_color);\nNK_API void nk_stroke_rect(struct nk_command_buffer*, struct nk_rect, float rounding, float line_thickness, struct nk_color);\nNK_API void nk_stroke_circle(struct nk_command_buffer*, struct nk_rect, float line_thickness, struct nk_color);\nNK_API void nk_stroke_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, float line_thickness, struct nk_color);\nNK_API void nk_stroke_triangle(struct nk_command_buffer*, float, float, float, float, float, float, float line_thichness, struct nk_color);\nNK_API void nk_stroke_polyline(struct nk_command_buffer*, const float *points, int point_count, float line_thickness, struct nk_color col);\nNK_API void nk_stroke_polygon(struct nk_command_buffer*, const float *points, int point_count, float line_thickness, struct nk_color);\n\n/** filled shades */\nNK_API void nk_fill_rect(struct nk_command_buffer*, struct nk_rect, float rounding, struct nk_color);\nNK_API void nk_fill_rect_multi_color(struct nk_command_buffer*, struct nk_rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom);\nNK_API void nk_fill_circle(struct nk_command_buffer*, struct nk_rect, struct nk_color);\nNK_API void nk_fill_arc(struct nk_command_buffer*, float cx, float cy, float radius, float a_min, float a_max, struct nk_color);\nNK_API void nk_fill_triangle(struct nk_command_buffer*, float x0, float y0, float x1, float y1, float x2, float y2, struct nk_color);\nNK_API void nk_fill_polygon(struct nk_command_buffer*, const float *points, int point_count, struct nk_color);\n\n/** misc */\nNK_API void nk_draw_image(struct nk_command_buffer*, struct nk_rect, const struct nk_image*, struct nk_color);\nNK_API void nk_draw_nine_slice(struct nk_command_buffer*, struct nk_rect, const struct nk_nine_slice*, struct nk_color);\nNK_API void nk_draw_text(struct nk_command_buffer*, struct nk_rect, const char *text, int len, const struct nk_user_font*, struct nk_color, struct nk_color);\nNK_API void nk_push_scissor(struct nk_command_buffer*, struct nk_rect);\nNK_API void nk_push_custom(struct nk_command_buffer*, struct nk_rect, nk_command_custom_callback, nk_handle usr);\n\n/* ===============================================================\n *\n *                          INPUT\n *\n * ===============================================================*/\nstruct nk_mouse_button {\n    nk_bool down;\n    unsigned int clicked;\n    struct nk_vec2 clicked_pos;\n};\nstruct nk_mouse {\n    struct nk_mouse_button buttons[NK_BUTTON_MAX];\n    struct nk_vec2 pos;\n#ifdef NK_BUTTON_TRIGGER_ON_RELEASE\n    struct nk_vec2 down_pos;\n#endif\n    struct nk_vec2 prev;\n    struct nk_vec2 delta;\n    struct nk_vec2 scroll_delta;\n    unsigned char grab;\n    unsigned char grabbed;\n    unsigned char ungrab;\n};\n\nstruct nk_key {\n    nk_bool down;\n    unsigned int clicked;\n};\nstruct nk_keyboard {\n    struct nk_key keys[NK_KEY_MAX];\n    char text[NK_INPUT_MAX];\n    int text_len;\n};\n\nstruct nk_input {\n    struct nk_keyboard keyboard;\n    struct nk_mouse mouse;\n};\n\nNK_API nk_bool nk_input_has_mouse_click(const struct nk_input*, enum nk_buttons);\nNK_API nk_bool nk_input_has_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);\nNK_API nk_bool nk_input_has_mouse_click_in_button_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);\nNK_API nk_bool nk_input_has_mouse_click_down_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect, nk_bool down);\nNK_API nk_bool nk_input_is_mouse_click_in_rect(const struct nk_input*, enum nk_buttons, struct nk_rect);\nNK_API nk_bool nk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id, struct nk_rect b, nk_bool down);\nNK_API nk_bool nk_input_any_mouse_click_in_rect(const struct nk_input*, struct nk_rect);\nNK_API nk_bool nk_input_is_mouse_prev_hovering_rect(const struct nk_input*, struct nk_rect);\nNK_API nk_bool nk_input_is_mouse_hovering_rect(const struct nk_input*, struct nk_rect);\nNK_API nk_bool nk_input_is_mouse_moved(const struct nk_input*);\nNK_API nk_bool nk_input_mouse_clicked(const struct nk_input*, enum nk_buttons, struct nk_rect);\nNK_API nk_bool nk_input_is_mouse_down(const struct nk_input*, enum nk_buttons);\nNK_API nk_bool nk_input_is_mouse_pressed(const struct nk_input*, enum nk_buttons);\nNK_API nk_bool nk_input_is_mouse_released(const struct nk_input*, enum nk_buttons);\nNK_API nk_bool nk_input_is_key_pressed(const struct nk_input*, enum nk_keys);\nNK_API nk_bool nk_input_is_key_released(const struct nk_input*, enum nk_keys);\nNK_API nk_bool nk_input_is_key_down(const struct nk_input*, enum nk_keys);\n\n/* ===============================================================\n *\n *                          DRAW LIST\n *\n * ===============================================================*/\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n/**\n * \\page \"Draw List\"\n * The optional vertex buffer draw list provides a 2D drawing context\n * with antialiasing functionality which takes basic filled or outlined shapes\n * or a path and outputs vertexes, elements and draw commands.\n * The actual draw list API is not required to be used directly while using this\n * library since converting the default library draw command output is done by\n * just calling `nk_convert` but I decided to still make this library accessible\n * since it can be useful.\n *\n * The draw list is based on a path buffering and polygon and polyline\n * rendering API which allows a lot of ways to draw 2D content to screen.\n * In fact it is probably more powerful than needed but allows even more crazy\n * things than this library provides by default.\n */\n\n#ifdef NK_UINT_DRAW_INDEX\ntypedef nk_uint nk_draw_index;\n#else\ntypedef nk_ushort nk_draw_index;\n#endif\nenum nk_draw_list_stroke {\n    NK_STROKE_OPEN = nk_false, /***< build up path has no connection back to the beginning */\n    NK_STROKE_CLOSED = nk_true /***< build up path has a connection back to the beginning */\n};\n\nenum nk_draw_vertex_layout_attribute {\n    NK_VERTEX_POSITION,\n    NK_VERTEX_COLOR,\n    NK_VERTEX_TEXCOORD,\n    NK_VERTEX_ATTRIBUTE_COUNT\n};\n\nenum nk_draw_vertex_layout_format {\n    NK_FORMAT_SCHAR,\n    NK_FORMAT_SSHORT,\n    NK_FORMAT_SINT,\n    NK_FORMAT_UCHAR,\n    NK_FORMAT_USHORT,\n    NK_FORMAT_UINT,\n    NK_FORMAT_FLOAT,\n    NK_FORMAT_DOUBLE,\n\nNK_FORMAT_COLOR_BEGIN,\n    NK_FORMAT_R8G8B8 = NK_FORMAT_COLOR_BEGIN,\n    NK_FORMAT_R16G15B16,\n    NK_FORMAT_R32G32B32,\n\n    NK_FORMAT_R8G8B8A8,\n    NK_FORMAT_B8G8R8A8,\n    NK_FORMAT_R16G15B16A16,\n    NK_FORMAT_R32G32B32A32,\n    NK_FORMAT_R32G32B32A32_FLOAT,\n    NK_FORMAT_R32G32B32A32_DOUBLE,\n\n    NK_FORMAT_RGB32,\n    NK_FORMAT_RGBA32,\nNK_FORMAT_COLOR_END = NK_FORMAT_RGBA32,\n    NK_FORMAT_COUNT\n};\n\n#define NK_VERTEX_LAYOUT_END NK_VERTEX_ATTRIBUTE_COUNT,NK_FORMAT_COUNT,0\nstruct nk_draw_vertex_layout_element {\n    enum nk_draw_vertex_layout_attribute attribute;\n    enum nk_draw_vertex_layout_format format;\n    nk_size offset;\n};\n\nstruct nk_draw_command {\n    unsigned int elem_count; /**< number of elements in the current draw batch */\n    struct nk_rect clip_rect; /**< current screen clipping rectangle */\n    nk_handle texture; /**< current texture to set */\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    nk_handle userdata;\n#endif\n};\n\nstruct nk_draw_list {\n    struct nk_rect clip_rect;\n    struct nk_vec2 circle_vtx[12];\n    struct nk_convert_config config;\n\n    struct nk_buffer *buffer;\n    struct nk_buffer *vertices;\n    struct nk_buffer *elements;\n\n    unsigned int element_count;\n    unsigned int vertex_count;\n    unsigned int cmd_count;\n    nk_size cmd_offset;\n\n    unsigned int path_count;\n    unsigned int path_offset;\n\n    enum nk_anti_aliasing line_AA;\n    enum nk_anti_aliasing shape_AA;\n\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    nk_handle userdata;\n#endif\n};\n\n/* draw list */\nNK_API void nk_draw_list_init(struct nk_draw_list*);\nNK_API void nk_draw_list_setup(struct nk_draw_list*, const struct nk_convert_config*, struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements, enum nk_anti_aliasing line_aa,enum nk_anti_aliasing shape_aa);\n\n/* drawing */\n#define nk_draw_list_foreach(cmd, can, b) for((cmd)=nk__draw_list_begin(can, b); (cmd)!=0; (cmd)=nk__draw_list_next(cmd, b, can))\nNK_API const struct nk_draw_command* nk__draw_list_begin(const struct nk_draw_list*, const struct nk_buffer*);\nNK_API const struct nk_draw_command* nk__draw_list_next(const struct nk_draw_command*, const struct nk_buffer*, const struct nk_draw_list*);\nNK_API const struct nk_draw_command* nk__draw_list_end(const struct nk_draw_list*, const struct nk_buffer*);\n\n/* path */\nNK_API void nk_draw_list_path_clear(struct nk_draw_list*);\nNK_API void nk_draw_list_path_line_to(struct nk_draw_list*, struct nk_vec2 pos);\nNK_API void nk_draw_list_path_arc_to_fast(struct nk_draw_list*, struct nk_vec2 center, float radius, int a_min, int a_max);\nNK_API void nk_draw_list_path_arc_to(struct nk_draw_list*, struct nk_vec2 center, float radius, float a_min, float a_max, unsigned int segments);\nNK_API void nk_draw_list_path_rect_to(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, float rounding);\nNK_API void nk_draw_list_path_curve_to(struct nk_draw_list*, struct nk_vec2 p2, struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments);\nNK_API void nk_draw_list_path_fill(struct nk_draw_list*, struct nk_color);\nNK_API void nk_draw_list_path_stroke(struct nk_draw_list*, struct nk_color, enum nk_draw_list_stroke closed, float thickness);\n\n/* stroke */\nNK_API void nk_draw_list_stroke_line(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_color, float thickness);\nNK_API void nk_draw_list_stroke_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding, float thickness);\nNK_API void nk_draw_list_stroke_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color, float thickness);\nNK_API void nk_draw_list_stroke_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color, unsigned int segs, float thickness);\nNK_API void nk_draw_list_stroke_curve(struct nk_draw_list*, struct nk_vec2 p0, struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1, struct nk_color, unsigned int segments, float thickness);\nNK_API void nk_draw_list_stroke_poly_line(struct nk_draw_list*, const struct nk_vec2 *pnts, const unsigned int cnt, struct nk_color, enum nk_draw_list_stroke, float thickness, enum nk_anti_aliasing);\n\n/* fill */\nNK_API void nk_draw_list_fill_rect(struct nk_draw_list*, struct nk_rect rect, struct nk_color, float rounding);\nNK_API void nk_draw_list_fill_rect_multi_color(struct nk_draw_list*, struct nk_rect rect, struct nk_color left, struct nk_color top, struct nk_color right, struct nk_color bottom);\nNK_API void nk_draw_list_fill_triangle(struct nk_draw_list*, struct nk_vec2 a, struct nk_vec2 b, struct nk_vec2 c, struct nk_color);\nNK_API void nk_draw_list_fill_circle(struct nk_draw_list*, struct nk_vec2 center, float radius, struct nk_color col, unsigned int segs);\nNK_API void nk_draw_list_fill_poly_convex(struct nk_draw_list*, const struct nk_vec2 *points, const unsigned int count, struct nk_color, enum nk_anti_aliasing);\n\n/* misc */\nNK_API void nk_draw_list_add_image(struct nk_draw_list*, struct nk_image texture, struct nk_rect rect, struct nk_color);\nNK_API void nk_draw_list_add_text(struct nk_draw_list*, const struct nk_user_font*, struct nk_rect, const char *text, int len, float font_height, struct nk_color);\n#ifdef NK_INCLUDE_COMMAND_USERDATA\nNK_API void nk_draw_list_push_userdata(struct nk_draw_list*, nk_handle userdata);\n#endif\n\n#endif\n\n/* ===============================================================\n *\n *                          GUI\n *\n * ===============================================================*/\nenum nk_style_item_type {\n    NK_STYLE_ITEM_COLOR,\n    NK_STYLE_ITEM_IMAGE,\n    NK_STYLE_ITEM_NINE_SLICE\n};\n\nunion nk_style_item_data {\n    struct nk_color color;\n    struct nk_image image;\n    struct nk_nine_slice slice;\n};\n\nstruct nk_style_item {\n    enum nk_style_item_type type;\n    union nk_style_item_data data;\n};\n\nstruct nk_style_text {\n    struct nk_color color;\n    struct nk_vec2 padding;\n    float color_factor;\n    float disabled_factor;\n};\n\nstruct nk_style_button {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n    float color_factor_background;\n\n    /* text */\n    struct nk_color text_background;\n    struct nk_color text_normal;\n    struct nk_color text_hover;\n    struct nk_color text_active;\n    nk_flags text_alignment;\n    float color_factor_text;\n\n    /* properties */\n    float border;\n    float rounding;\n    struct nk_vec2 padding;\n    struct nk_vec2 image_padding;\n    struct nk_vec2 touch_padding;\n    float disabled_factor;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle userdata);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle userdata);\n};\n\nstruct nk_style_toggle {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* cursor */\n    struct nk_style_item cursor_normal;\n    struct nk_style_item cursor_hover;\n\n    /* text */\n    struct nk_color text_normal;\n    struct nk_color text_hover;\n    struct nk_color text_active;\n    struct nk_color text_background;\n    nk_flags text_alignment;\n\n    /* properties */\n    struct nk_vec2 padding;\n    struct nk_vec2 touch_padding;\n    float spacing;\n    float border;\n    float color_factor;\n    float disabled_factor;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_selectable {\n    /* background (inactive) */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item pressed;\n\n    /* background (active) */\n    struct nk_style_item normal_active;\n    struct nk_style_item hover_active;\n    struct nk_style_item pressed_active;\n\n    /* text color (inactive) */\n    struct nk_color text_normal;\n    struct nk_color text_hover;\n    struct nk_color text_pressed;\n\n    /* text color (active) */\n    struct nk_color text_normal_active;\n    struct nk_color text_hover_active;\n    struct nk_color text_pressed_active;\n    struct nk_color text_background;\n    nk_flags text_alignment;\n\n    /* properties */\n    float rounding;\n    struct nk_vec2 padding;\n    struct nk_vec2 touch_padding;\n    struct nk_vec2 image_padding;\n    float color_factor;\n    float disabled_factor;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_slider {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* background bar */\n    struct nk_color bar_normal;\n    struct nk_color bar_hover;\n    struct nk_color bar_active;\n    struct nk_color bar_filled;\n\n    /* cursor */\n    struct nk_style_item cursor_normal;\n    struct nk_style_item cursor_hover;\n    struct nk_style_item cursor_active;\n\n    /* properties */\n    float border;\n    float rounding;\n    float bar_height;\n    struct nk_vec2 padding;\n    struct nk_vec2 spacing;\n    struct nk_vec2 cursor_size;\n    float color_factor;\n    float disabled_factor;\n\n    /* optional buttons */\n    int show_buttons;\n    struct nk_style_button inc_button;\n    struct nk_style_button dec_button;\n    enum nk_symbol_type inc_symbol;\n    enum nk_symbol_type dec_symbol;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_knob {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* knob */\n    struct nk_color knob_normal;\n    struct nk_color knob_hover;\n    struct nk_color knob_active;\n    struct nk_color knob_border_color;\n\n    /* cursor */\n    struct nk_color cursor_normal;\n    struct nk_color cursor_hover;\n    struct nk_color cursor_active;\n\n    /* properties */\n    float border;\n    float knob_border;\n    struct nk_vec2 padding;\n    struct nk_vec2 spacing;\n    float cursor_width;\n    float color_factor;\n    float disabled_factor;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_progress {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* cursor */\n    struct nk_style_item cursor_normal;\n    struct nk_style_item cursor_hover;\n    struct nk_style_item cursor_active;\n    struct nk_color cursor_border_color;\n\n    /* properties */\n    float rounding;\n    float border;\n    float cursor_border;\n    float cursor_rounding;\n    struct nk_vec2 padding;\n    float color_factor;\n    float disabled_factor;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_scrollbar {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* cursor */\n    struct nk_style_item cursor_normal;\n    struct nk_style_item cursor_hover;\n    struct nk_style_item cursor_active;\n    struct nk_color cursor_border_color;\n\n    /* properties */\n    float border;\n    float rounding;\n    float border_cursor;\n    float rounding_cursor;\n    struct nk_vec2 padding;\n    float color_factor;\n    float disabled_factor;\n\n    /* optional buttons */\n    int show_buttons;\n    struct nk_style_button inc_button;\n    struct nk_style_button dec_button;\n    enum nk_symbol_type inc_symbol;\n    enum nk_symbol_type dec_symbol;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_edit {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n    struct nk_style_scrollbar scrollbar;\n\n    /* cursor  */\n    struct nk_color cursor_normal;\n    struct nk_color cursor_hover;\n    struct nk_color cursor_text_normal;\n    struct nk_color cursor_text_hover;\n\n    /* text (unselected) */\n    struct nk_color text_normal;\n    struct nk_color text_hover;\n    struct nk_color text_active;\n\n    /* text (selected) */\n    struct nk_color selected_normal;\n    struct nk_color selected_hover;\n    struct nk_color selected_text_normal;\n    struct nk_color selected_text_hover;\n\n    /* properties */\n    float border;\n    float rounding;\n    float cursor_size;\n    struct nk_vec2 scrollbar_size;\n    struct nk_vec2 padding;\n    float row_padding;\n    float color_factor;\n    float disabled_factor;\n};\n\nstruct nk_style_property {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* text */\n    struct nk_color label_normal;\n    struct nk_color label_hover;\n    struct nk_color label_active;\n\n    /* symbols */\n    enum nk_symbol_type sym_left;\n    enum nk_symbol_type sym_right;\n\n    /* properties */\n    float border;\n    float rounding;\n    struct nk_vec2 padding;\n    float color_factor;\n    float disabled_factor;\n\n    struct nk_style_edit edit;\n    struct nk_style_button inc_button;\n    struct nk_style_button dec_button;\n\n    /* optional user callbacks */\n    nk_handle userdata;\n    void(*draw_begin)(struct nk_command_buffer*, nk_handle);\n    void(*draw_end)(struct nk_command_buffer*, nk_handle);\n};\n\nstruct nk_style_chart {\n    /* colors */\n    struct nk_style_item background;\n    struct nk_color border_color;\n    struct nk_color selected_color;\n    struct nk_color color;\n\n    /* properties */\n    float border;\n    float rounding;\n    struct nk_vec2 padding;\n    float color_factor;\n    float disabled_factor;\n    nk_bool show_markers;\n};\n\nstruct nk_style_combo {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n    struct nk_color border_color;\n\n    /* label */\n    struct nk_color label_normal;\n    struct nk_color label_hover;\n    struct nk_color label_active;\n\n    /* symbol */\n    struct nk_color symbol_normal;\n    struct nk_color symbol_hover;\n    struct nk_color symbol_active;\n\n    /* button */\n    struct nk_style_button button;\n    enum nk_symbol_type sym_normal;\n    enum nk_symbol_type sym_hover;\n    enum nk_symbol_type sym_active;\n\n    /* properties */\n    float border;\n    float rounding;\n    struct nk_vec2 content_padding;\n    struct nk_vec2 button_padding;\n    struct nk_vec2 spacing;\n    float color_factor;\n    float disabled_factor;\n};\n\nstruct nk_style_tab {\n    /* background */\n    struct nk_style_item background;\n    struct nk_color border_color;\n    struct nk_color text;\n\n    /* button */\n    struct nk_style_button tab_maximize_button;\n    struct nk_style_button tab_minimize_button;\n    struct nk_style_button node_maximize_button;\n    struct nk_style_button node_minimize_button;\n    enum nk_symbol_type sym_minimize;\n    enum nk_symbol_type sym_maximize;\n\n    /* properties */\n    float border;\n    float rounding;\n    float indent;\n    struct nk_vec2 padding;\n    struct nk_vec2 spacing;\n    float color_factor;\n    float disabled_factor;\n};\n\nenum nk_style_header_align {\n    NK_HEADER_LEFT,\n    NK_HEADER_RIGHT\n};\nstruct nk_style_window_header {\n    /* background */\n    struct nk_style_item normal;\n    struct nk_style_item hover;\n    struct nk_style_item active;\n\n    /* button */\n    struct nk_style_button close_button;\n    struct nk_style_button minimize_button;\n    enum nk_symbol_type close_symbol;\n    enum nk_symbol_type minimize_symbol;\n    enum nk_symbol_type maximize_symbol;\n\n    /* title */\n    struct nk_color label_normal;\n    struct nk_color label_hover;\n    struct nk_color label_active;\n\n    /* properties */\n    enum nk_style_header_align align;\n    struct nk_vec2 padding;\n    struct nk_vec2 label_padding;\n    struct nk_vec2 spacing;\n};\n\nstruct nk_style_window {\n    struct nk_style_window_header header;\n    struct nk_style_item fixed_background;\n    struct nk_color background;\n\n    struct nk_color border_color;\n    struct nk_color popup_border_color;\n    struct nk_color combo_border_color;\n    struct nk_color contextual_border_color;\n    struct nk_color menu_border_color;\n    struct nk_color group_border_color;\n    struct nk_color tooltip_border_color;\n    struct nk_style_item scaler;\n\n    float border;\n    float combo_border;\n    float contextual_border;\n    float menu_border;\n    float group_border;\n    float tooltip_border;\n    float popup_border;\n    float min_row_height_padding;\n\n    float rounding;\n    struct nk_vec2 spacing;\n    struct nk_vec2 scrollbar_size;\n    struct nk_vec2 min_size;\n\n    struct nk_vec2 padding;\n    struct nk_vec2 group_padding;\n    struct nk_vec2 popup_padding;\n    struct nk_vec2 combo_padding;\n    struct nk_vec2 contextual_padding;\n    struct nk_vec2 menu_padding;\n    struct nk_vec2 tooltip_padding;\n\n    enum nk_tooltip_pos tooltip_origin;\n    struct nk_vec2 tooltip_offset;\n};\n\nstruct nk_style {\n    const struct nk_user_font *font;\n    const struct nk_cursor *cursors[NK_CURSOR_COUNT];\n    const struct nk_cursor *cursor_active;\n    struct nk_cursor *cursor_last;\n    int cursor_visible;\n\n    struct nk_style_text text;\n    struct nk_style_button button;\n    struct nk_style_button contextual_button;\n    struct nk_style_button menu_button;\n    struct nk_style_toggle option;\n    struct nk_style_toggle checkbox;\n    struct nk_style_selectable selectable;\n    struct nk_style_slider slider;\n    struct nk_style_knob knob;\n    struct nk_style_progress progress;\n    struct nk_style_property property;\n    struct nk_style_edit edit;\n    struct nk_style_chart chart;\n    struct nk_style_scrollbar scrollh;\n    struct nk_style_scrollbar scrollv;\n    struct nk_style_tab tab;\n    struct nk_style_combo combo;\n    struct nk_style_window window;\n};\n\nNK_API struct nk_style_item nk_style_item_color(struct nk_color);\nNK_API struct nk_style_item nk_style_item_image(struct nk_image img);\nNK_API struct nk_style_item nk_style_item_nine_slice(struct nk_nine_slice slice);\nNK_API struct nk_style_item nk_style_item_hide(void);\n\n/*==============================================================\n *                          PANEL\n * =============================================================*/\n#ifndef NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS\n#define NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS 16\n#endif\n#ifndef NK_CHART_MAX_SLOT\n#define NK_CHART_MAX_SLOT 4\n#endif\n\nenum nk_panel_type {\n    NK_PANEL_NONE       = 0,\n    NK_PANEL_WINDOW     = NK_FLAG(0),\n    NK_PANEL_GROUP      = NK_FLAG(1),\n    NK_PANEL_POPUP      = NK_FLAG(2),\n    NK_PANEL_CONTEXTUAL = NK_FLAG(4),\n    NK_PANEL_COMBO      = NK_FLAG(5),\n    NK_PANEL_MENU       = NK_FLAG(6),\n    NK_PANEL_TOOLTIP    = NK_FLAG(7)\n};\nenum nk_panel_set {\n    NK_PANEL_SET_NONBLOCK = NK_PANEL_CONTEXTUAL|NK_PANEL_COMBO|NK_PANEL_MENU|NK_PANEL_TOOLTIP,\n    NK_PANEL_SET_POPUP = NK_PANEL_SET_NONBLOCK|NK_PANEL_POPUP,\n    NK_PANEL_SET_SUB = NK_PANEL_SET_POPUP|NK_PANEL_GROUP\n};\n\nstruct nk_chart_slot {\n    enum nk_chart_type type;\n    struct nk_color color;\n    struct nk_color highlight;\n    float min, max, range;\n    int count;\n    struct nk_vec2 last;\n    int index;\n    nk_bool show_markers;\n};\n\nstruct nk_chart {\n    int slot;\n    float x, y, w, h;\n    struct nk_chart_slot slots[NK_CHART_MAX_SLOT];\n};\n\nenum nk_panel_row_layout_type {\n    NK_LAYOUT_DYNAMIC_FIXED = 0,\n    NK_LAYOUT_DYNAMIC_ROW,\n    NK_LAYOUT_DYNAMIC_FREE,\n    NK_LAYOUT_DYNAMIC,\n    NK_LAYOUT_STATIC_FIXED,\n    NK_LAYOUT_STATIC_ROW,\n    NK_LAYOUT_STATIC_FREE,\n    NK_LAYOUT_STATIC,\n    NK_LAYOUT_TEMPLATE,\n    NK_LAYOUT_COUNT\n};\nstruct nk_row_layout {\n    enum nk_panel_row_layout_type type;\n    int index;\n    float height;\n    float min_height;\n    int columns;\n    const float *ratio;\n    float item_width;\n    float item_height;\n    float item_offset;\n    float filled;\n    struct nk_rect item;\n    int tree_depth;\n    float templates[NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS];\n};\n\nstruct nk_popup_buffer {\n    nk_size begin;\n    nk_size parent;\n    nk_size last;\n    nk_size end;\n    nk_bool active;\n};\n\nstruct nk_menu_state {\n    float x, y, w, h;\n    struct nk_scroll offset;\n};\n\nstruct nk_panel {\n    enum nk_panel_type type;\n    nk_flags flags;\n    struct nk_rect bounds;\n    nk_uint *offset_x;\n    nk_uint *offset_y;\n    float at_x, at_y, max_x;\n    float footer_height;\n    float header_height;\n    float border;\n    unsigned int has_scrolling;\n    struct nk_rect clip;\n    struct nk_menu_state menu;\n    struct nk_row_layout row;\n    struct nk_chart chart;\n    struct nk_command_buffer *buffer;\n    struct nk_panel *parent;\n};\n\n/*==============================================================\n *                          WINDOW\n * =============================================================*/\n#ifndef NK_WINDOW_MAX_NAME\n#define NK_WINDOW_MAX_NAME 64\n#endif\n\nstruct nk_table;\nenum nk_window_flags {\n    NK_WINDOW_PRIVATE       = NK_FLAG(11),\n    NK_WINDOW_DYNAMIC       = NK_WINDOW_PRIVATE,                  /**< special window type growing up in height while being filled to a certain maximum height */\n    NK_WINDOW_ROM           = NK_FLAG(12),                        /**< sets window widgets into a read only mode and does not allow input changes */\n    NK_WINDOW_NOT_INTERACTIVE = NK_WINDOW_ROM|NK_WINDOW_NO_INPUT, /**< prevents all interaction caused by input to either window or widgets inside */\n    NK_WINDOW_HIDDEN        = NK_FLAG(13),                        /**< Hides window and stops any window interaction and drawing */\n    NK_WINDOW_CLOSED        = NK_FLAG(14),                        /**< Directly closes and frees the window at the end of the frame */\n    NK_WINDOW_MINIMIZED     = NK_FLAG(15),                        /**< marks the window as minimized */\n    NK_WINDOW_REMOVE_ROM    = NK_FLAG(16)                         /**< Removes read only mode at the end of the window */\n};\n\nstruct nk_popup_state {\n    struct nk_window *win;\n    enum nk_panel_type type;\n    struct nk_popup_buffer buf;\n    nk_hash name;\n    nk_bool active;\n    unsigned combo_count;\n    unsigned con_count, con_old;\n    unsigned active_con;\n    struct nk_rect header;\n};\n\nstruct nk_edit_state {\n    nk_hash name;\n    unsigned int seq;\n    unsigned int old;\n    int active, prev;\n    int cursor;\n    int sel_start;\n    int sel_end;\n    struct nk_scroll scrollbar;\n    unsigned char mode;\n    unsigned char single_line;\n};\n\nstruct nk_property_state {\n    int active, prev;\n    char buffer[NK_MAX_NUMBER_BUFFER];\n    int length;\n    int cursor;\n    int select_start;\n    int select_end;\n    nk_hash name;\n    unsigned int seq;\n    unsigned int old;\n    int state;\n    int prev_state;\n    nk_hash prev_name;\n    char prev_buffer[NK_MAX_NUMBER_BUFFER];\n    int prev_length;\n};\n\nstruct nk_window {\n    unsigned int seq;\n    nk_hash name;\n    char name_string[NK_WINDOW_MAX_NAME];\n    nk_flags flags;\n\n    struct nk_rect bounds;\n    struct nk_scroll scrollbar;\n    struct nk_command_buffer buffer;\n    struct nk_panel *layout;\n    float scrollbar_hiding_timer;\n\n    /* persistent widget state */\n    struct nk_property_state property;\n    struct nk_popup_state popup;\n    struct nk_edit_state edit;\n    unsigned int scrolled;\n    nk_bool widgets_disabled;\n\n    struct nk_table *tables;\n    unsigned int table_count;\n\n    /* window list hooks */\n    struct nk_window *next;\n    struct nk_window *prev;\n    struct nk_window *parent;\n};\n\n/*==============================================================\n *                          STACK\n * =============================================================*/\n/**\n * \\page Stack\n * The style modifier stack can be used to temporarily change a\n * property inside `nk_style`. For example if you want a special\n * red button you can temporarily push the old button color onto a stack\n * draw the button with a red color and then you just pop the old color\n * back from the stack:\n *\n *     nk_style_push_style_item(ctx, &ctx->style.button.normal, nk_style_item_color(nk_rgb(255,0,0)));\n *     nk_style_push_style_item(ctx, &ctx->style.button.hover, nk_style_item_color(nk_rgb(255,0,0)));\n *     nk_style_push_style_item(ctx, &ctx->style.button.active, nk_style_item_color(nk_rgb(255,0,0)));\n *     nk_style_push_vec2(ctx, &cx->style.button.padding, nk_vec2(2,2));\n *\n *     nk_button(...);\n *\n *     nk_style_pop_style_item(ctx);\n *     nk_style_pop_style_item(ctx);\n *     nk_style_pop_style_item(ctx);\n *     nk_style_pop_vec2(ctx);\n *\n * Nuklear has a stack for style_items, float properties, vector properties,\n * flags, colors, fonts and for button_behavior. Each has it's own fixed size stack\n * which can be changed at compile time.\n */\n\n#ifndef NK_BUTTON_BEHAVIOR_STACK_SIZE\n#define NK_BUTTON_BEHAVIOR_STACK_SIZE 8\n#endif\n\n#ifndef NK_FONT_STACK_SIZE\n#define NK_FONT_STACK_SIZE 8\n#endif\n\n#ifndef NK_STYLE_ITEM_STACK_SIZE\n#define NK_STYLE_ITEM_STACK_SIZE 16\n#endif\n\n#ifndef NK_FLOAT_STACK_SIZE\n#define NK_FLOAT_STACK_SIZE 32\n#endif\n\n#ifndef NK_VECTOR_STACK_SIZE\n#define NK_VECTOR_STACK_SIZE 16\n#endif\n\n#ifndef NK_FLAGS_STACK_SIZE\n#define NK_FLAGS_STACK_SIZE 32\n#endif\n\n#ifndef NK_COLOR_STACK_SIZE\n#define NK_COLOR_STACK_SIZE 32\n#endif\n\n#define NK_CONFIGURATION_STACK_TYPE(prefix, name, type)\\\n    struct nk_config_stack_##name##_element {\\\n        prefix##_##type *address;\\\n        prefix##_##type old_value;\\\n    }\n#define NK_CONFIG_STACK(type,size)\\\n    struct nk_config_stack_##type {\\\n        int head;\\\n        struct nk_config_stack_##type##_element elements[size];\\\n    }\n\n#define nk_float float\nNK_CONFIGURATION_STACK_TYPE(struct nk, style_item, style_item);\nNK_CONFIGURATION_STACK_TYPE(nk ,float, float);\nNK_CONFIGURATION_STACK_TYPE(struct nk, vec2, vec2);\nNK_CONFIGURATION_STACK_TYPE(nk ,flags, flags);\nNK_CONFIGURATION_STACK_TYPE(struct nk, color, color);\nNK_CONFIGURATION_STACK_TYPE(const struct nk, user_font, user_font*);\nNK_CONFIGURATION_STACK_TYPE(enum nk, button_behavior, button_behavior);\n\nNK_CONFIG_STACK(style_item, NK_STYLE_ITEM_STACK_SIZE);\nNK_CONFIG_STACK(float, NK_FLOAT_STACK_SIZE);\nNK_CONFIG_STACK(vec2, NK_VECTOR_STACK_SIZE);\nNK_CONFIG_STACK(flags, NK_FLAGS_STACK_SIZE);\nNK_CONFIG_STACK(color, NK_COLOR_STACK_SIZE);\nNK_CONFIG_STACK(user_font, NK_FONT_STACK_SIZE);\nNK_CONFIG_STACK(button_behavior, NK_BUTTON_BEHAVIOR_STACK_SIZE);\n\nstruct nk_configuration_stacks {\n    struct nk_config_stack_style_item style_items;\n    struct nk_config_stack_float floats;\n    struct nk_config_stack_vec2 vectors;\n    struct nk_config_stack_flags flags;\n    struct nk_config_stack_color colors;\n    struct nk_config_stack_user_font fonts;\n    struct nk_config_stack_button_behavior button_behaviors;\n};\n\n/*==============================================================\n *                          CONTEXT\n * =============================================================*/\n#define NK_VALUE_PAGE_CAPACITY \\\n    (((NK_MAX(sizeof(struct nk_window),sizeof(struct nk_panel)) / sizeof(nk_uint))) / 2)\n\nstruct nk_table {\n    unsigned int seq;\n    unsigned int size;\n    nk_hash keys[NK_VALUE_PAGE_CAPACITY];\n    nk_uint values[NK_VALUE_PAGE_CAPACITY];\n    struct nk_table *next, *prev;\n};\n\nunion nk_page_data {\n    struct nk_table tbl;\n    struct nk_panel pan;\n    struct nk_window win;\n};\n\nstruct nk_page_element {\n    union nk_page_data data;\n    struct nk_page_element *next;\n    struct nk_page_element *prev;\n};\n\nstruct nk_page {\n    unsigned int size;\n    struct nk_page *next;\n    struct nk_page_element win[1];\n};\n\nstruct nk_pool {\n    struct nk_allocator alloc;\n    enum nk_allocation_type type;\n    unsigned int page_count;\n    struct nk_page *pages;\n    struct nk_page_element *freelist;\n    unsigned capacity;\n    nk_size size;\n    nk_size cap;\n};\n\nstruct nk_context {\n/* public: can be accessed freely */\n    struct nk_input input;\n    struct nk_style style;\n    struct nk_buffer memory;\n    struct nk_clipboard clip;\n    nk_flags last_widget_state;\n    enum nk_button_behavior button_behavior;\n    struct nk_configuration_stacks stacks;\n    float delta_time_seconds;\n\n/* private:\n    should only be accessed if you\n    know what you are doing */\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n    struct nk_draw_list draw_list;\n#endif\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    nk_handle userdata;\n#endif\n    /** text editor objects are quite big because of an internal\n     * undo/redo stack. Therefore it does not make sense to have one for\n     * each window for temporary use cases, so I only provide *one* instance\n     * for all windows. This works because the content is cleared anyway */\n    struct nk_text_edit text_edit;\n    /** draw buffer used for overlay drawing operation like cursor */\n    struct nk_command_buffer overlay;\n\n    /** windows */\n    int build;\n    int use_pool;\n    struct nk_pool pool;\n    struct nk_window *begin;\n    struct nk_window *end;\n    struct nk_window *active;\n    struct nk_window *current;\n    struct nk_page_element *freelist;\n    unsigned int count;\n    unsigned int seq;\n};\n\n/* ==============================================================\n *                          MATH\n * =============================================================== */\n#define NK_PI 3.141592654f\n#define NK_PI_HALF 1.570796326f\n#define NK_UTF_INVALID 0xFFFD\n#define NK_MAX_FLOAT_PRECISION 2\n\n#define NK_UNUSED(x) ((void)(x))\n#define NK_SATURATE(x) (NK_MAX(0, NK_MIN(1.0f, x)))\n#define NK_LEN(a) (sizeof(a)/sizeof(a)[0])\n#define NK_ABS(a) (((a) < 0) ? -(a) : (a))\n#define NK_BETWEEN(x, a, b) ((a) <= (x) && (x) < (b))\n#define NK_INBOX(px, py, x, y, w, h)\\\n    (NK_BETWEEN(px,x,x+w) && NK_BETWEEN(py,y,y+h))\n#define NK_INTERSECT(x0, y0, w0, h0, x1, y1, w1, h1) \\\n    ((x1 < (x0 + w0)) && (x0 < (x1 + w1)) && \\\n    (y1 < (y0 + h0)) && (y0 < (y1 + h1)))\n#define NK_CONTAINS(x, y, w, h, bx, by, bw, bh)\\\n    (NK_INBOX(x,y, bx, by, bw, bh) && NK_INBOX(x+w,y+h, bx, by, bw, bh))\n\n#define nk_vec2_sub(a, b) nk_vec2((a).x - (b).x, (a).y - (b).y)\n#define nk_vec2_add(a, b) nk_vec2((a).x + (b).x, (a).y + (b).y)\n#define nk_vec2_len_sqr(a) ((a).x*(a).x+(a).y*(a).y)\n#define nk_vec2_muls(a, t) nk_vec2((a).x * (t), (a).y * (t))\n\n#define nk_ptr_add(t, p, i) ((t*)((void*)((nk_byte*)(p) + (i))))\n#define nk_ptr_add_const(t, p, i) ((const t*)((const void*)((const nk_byte*)(p) + (i))))\n#define nk_zero_struct(s) nk_zero(&s, sizeof(s))\n\n/* ==============================================================\n *                          ALIGNMENT\n * =============================================================== */\n/* Pointer to Integer type conversion for pointer alignment */\n#if defined(__PTRDIFF_TYPE__) /* This case should work for GCC*/\n# define NK_UINT_TO_PTR(x) ((void*)(__PTRDIFF_TYPE__)(x))\n# define NK_PTR_TO_UINT(x) ((nk_size)(__PTRDIFF_TYPE__)(x))\n#elif !defined(__GNUC__) /* works for compilers other than LLVM */\n# define NK_UINT_TO_PTR(x) ((void*)&((char*)0)[x])\n# define NK_PTR_TO_UINT(x) ((nk_size)(((char*)x)-(char*)0))\n#elif defined(NK_USE_FIXED_TYPES) /* used if we have <stdint.h> */\n# define NK_UINT_TO_PTR(x) ((void*)(uintptr_t)(x))\n# define NK_PTR_TO_UINT(x) ((uintptr_t)(x))\n#else /* generates warning but works */\n# define NK_UINT_TO_PTR(x) ((void*)(x))\n# define NK_PTR_TO_UINT(x) ((nk_size)(x))\n#endif\n\n#define NK_ALIGN_PTR(x, mask)\\\n    (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x) + (mask-1)) & ~(mask-1))))\n#define NK_ALIGN_PTR_BACK(x, mask)\\\n    (NK_UINT_TO_PTR((NK_PTR_TO_UINT((nk_byte*)(x)) & ~(mask-1))))\n\n#if ((defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)) && !defined(EMSCRIPTEN)\n#define NK_OFFSETOF(st,m) (__builtin_offsetof(st,m))\n#else\n#define NK_OFFSETOF(st,m) ((nk_ptr)&(((st*)0)->m))\n#endif\n\n#ifdef __cplusplus\n}\n#endif\n\n#ifdef __cplusplus\ntemplate<typename T> struct nk_alignof;\ntemplate<typename T, int size_diff> struct nk_helper{enum {value = size_diff};};\ntemplate<typename T> struct nk_helper<T,0>{enum {value = nk_alignof<T>::value};};\ntemplate<typename T> struct nk_alignof{struct Big {T x; char c;}; enum {\n    diff = sizeof(Big) - sizeof(T), value = nk_helper<Big, diff>::value};};\n#define NK_ALIGNOF(t) (nk_alignof<t>::value)\n#else\n#define NK_ALIGNOF(t) NK_OFFSETOF(struct {char c; t _h;}, _h)\n#endif\n\n#define NK_CONTAINER_OF(ptr,type,member)\\\n    (type*)((void*)((char*)(1 ? (ptr): &((type*)0)->member) - NK_OFFSETOF(type, member)))\n\n\n\n#endif /* NK_NUKLEAR_H_ */\n"
  },
  {
    "path": "src/nuklear_9slice.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                          9-SLICE\n *\n * ===============================================================*/\nNK_API struct nk_nine_slice\nnk_sub9slice_ptr(void *ptr, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)\n{\n    struct nk_nine_slice s;\n    struct nk_image *i = &s.img;\n    nk_zero(&s, sizeof(s));\n    i->handle.ptr = ptr;\n    i->w = w; i->h = h;\n    i->region[0] = (nk_ushort)rgn.x;\n    i->region[1] = (nk_ushort)rgn.y;\n    i->region[2] = (nk_ushort)rgn.w;\n    i->region[3] = (nk_ushort)rgn.h;\n    s.l = l; s.t = t; s.r = r; s.b = b;\n    return s;\n}\nNK_API struct nk_nine_slice\nnk_sub9slice_id(int id, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)\n{\n    struct nk_nine_slice s;\n    struct nk_image *i = &s.img;\n    nk_zero(&s, sizeof(s));\n    i->handle.id = id;\n    i->w = w; i->h = h;\n    i->region[0] = (nk_ushort)rgn.x;\n    i->region[1] = (nk_ushort)rgn.y;\n    i->region[2] = (nk_ushort)rgn.w;\n    i->region[3] = (nk_ushort)rgn.h;\n    s.l = l; s.t = t; s.r = r; s.b = b;\n    return s;\n}\nNK_API struct nk_nine_slice\nnk_sub9slice_handle(nk_handle handle, nk_ushort w, nk_ushort h, struct nk_rect rgn, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)\n{\n    struct nk_nine_slice s;\n    struct nk_image *i = &s.img;\n    nk_zero(&s, sizeof(s));\n    i->handle = handle;\n    i->w = w; i->h = h;\n    i->region[0] = (nk_ushort)rgn.x;\n    i->region[1] = (nk_ushort)rgn.y;\n    i->region[2] = (nk_ushort)rgn.w;\n    i->region[3] = (nk_ushort)rgn.h;\n    s.l = l; s.t = t; s.r = r; s.b = b;\n    return s;\n}\nNK_API struct nk_nine_slice\nnk_nine_slice_handle(nk_handle handle, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)\n{\n    struct nk_nine_slice s;\n    struct nk_image *i = &s.img;\n    nk_zero(&s, sizeof(s));\n    i->handle = handle;\n    i->w = 0; i->h = 0;\n    i->region[0] = 0;\n    i->region[1] = 0;\n    i->region[2] = 0;\n    i->region[3] = 0;\n    s.l = l; s.t = t; s.r = r; s.b = b;\n    return s;\n}\nNK_API struct nk_nine_slice\nnk_nine_slice_ptr(void *ptr, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)\n{\n    struct nk_nine_slice s;\n    struct nk_image *i = &s.img;\n    nk_zero(&s, sizeof(s));\n    NK_ASSERT(ptr);\n    i->handle.ptr = ptr;\n    i->w = 0; i->h = 0;\n    i->region[0] = 0;\n    i->region[1] = 0;\n    i->region[2] = 0;\n    i->region[3] = 0;\n    s.l = l; s.t = t; s.r = r; s.b = b;\n    return s;\n}\nNK_API struct nk_nine_slice\nnk_nine_slice_id(int id, nk_ushort l, nk_ushort t, nk_ushort r, nk_ushort b)\n{\n    struct nk_nine_slice s;\n    struct nk_image *i = &s.img;\n    nk_zero(&s, sizeof(s));\n    i->handle.id = id;\n    i->w = 0; i->h = 0;\n    i->region[0] = 0;\n    i->region[1] = 0;\n    i->region[2] = 0;\n    i->region[3] = 0;\n    s.l = l; s.t = t; s.r = r; s.b = b;\n    return s;\n}\nNK_API int\nnk_nine_slice_is_sub9slice(const struct nk_nine_slice* slice)\n{\n    NK_ASSERT(slice);\n    return !(slice->img.w == 0 && slice->img.h == 0);\n}\n\n"
  },
  {
    "path": "src/nuklear_buffer.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ==============================================================\n *\n *                          BUFFER\n *\n * ===============================================================*/\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_LIB void*\nnk_malloc(nk_handle unused, void *old,nk_size size)\n{\n    NK_UNUSED(unused);\n    NK_UNUSED(old);\n    return malloc(size);\n}\nNK_LIB void\nnk_mfree(nk_handle unused, void *ptr)\n{\n    NK_UNUSED(unused);\n    free(ptr);\n}\nNK_API void\nnk_buffer_init_default(struct nk_buffer *buffer)\n{\n    struct nk_allocator alloc;\n    alloc.userdata.ptr = 0;\n    alloc.alloc = nk_malloc;\n    alloc.free = nk_mfree;\n    nk_buffer_init(buffer, &alloc, NK_BUFFER_DEFAULT_INITIAL_SIZE);\n}\n#endif\n\nNK_API void\nnk_buffer_init(struct nk_buffer *b, const struct nk_allocator *a,\n    nk_size initial_size)\n{\n    NK_ASSERT(b);\n    NK_ASSERT(a);\n    NK_ASSERT(initial_size);\n    if (!b || !a || !initial_size) return;\n\n    nk_zero(b, sizeof(*b));\n    b->type = NK_BUFFER_DYNAMIC;\n    b->memory.ptr = a->alloc(a->userdata,0, initial_size);\n    b->memory.size = initial_size;\n    b->size = initial_size;\n    b->grow_factor = 2.0f;\n    b->pool = *a;\n}\nNK_API void\nnk_buffer_init_fixed(struct nk_buffer *b, void *m, nk_size size)\n{\n    NK_ASSERT(b);\n    NK_ASSERT(m);\n    NK_ASSERT(size);\n    if (!b || !m || !size) return;\n\n    nk_zero(b, sizeof(*b));\n    b->type = NK_BUFFER_FIXED;\n    b->memory.ptr = m;\n    b->memory.size = size;\n    b->size = size;\n}\nNK_LIB void*\nnk_buffer_align(void *unaligned,\n    nk_size align, nk_size *alignment,\n    enum nk_buffer_allocation_type type)\n{\n    void *memory = 0;\n    switch (type) {\n    default:\n    case NK_BUFFER_MAX:\n    case NK_BUFFER_FRONT:\n        if (align) {\n            memory = NK_ALIGN_PTR(unaligned, align);\n            *alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);\n        } else {\n            memory = unaligned;\n            *alignment = 0;\n        }\n        break;\n    case NK_BUFFER_BACK:\n        if (align) {\n            memory = NK_ALIGN_PTR_BACK(unaligned, align);\n            *alignment = (nk_size)((nk_byte*)unaligned - (nk_byte*)memory);\n        } else {\n            memory = unaligned;\n            *alignment = 0;\n        }\n        break;\n    }\n    return memory;\n}\nNK_LIB void*\nnk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size)\n{\n    void *temp;\n    nk_size buffer_size;\n\n    NK_ASSERT(b);\n    NK_ASSERT(size);\n    if (!b || !size || !b->pool.alloc || !b->pool.free)\n        return 0;\n\n    buffer_size = b->memory.size;\n    temp = b->pool.alloc(b->pool.userdata, b->memory.ptr, capacity);\n    NK_ASSERT(temp);\n    if (!temp) return 0;\n\n    *size = capacity;\n    if (temp != b->memory.ptr) {\n        NK_MEMCPY(temp, b->memory.ptr, buffer_size);\n        b->pool.free(b->pool.userdata, b->memory.ptr);\n    }\n\n    if (b->size == buffer_size) {\n        /* no back buffer so just set correct size */\n        b->size = capacity;\n        return temp;\n    } else {\n        /* copy back buffer to the end of the new buffer */\n        void *dst, *src;\n        nk_size back_size;\n        back_size = buffer_size - b->size;\n        dst = nk_ptr_add(void, temp, capacity - back_size);\n        src = nk_ptr_add(void, temp, b->size);\n        NK_MEMCPY(dst, src, back_size);\n        b->size = capacity - back_size;\n    }\n    return temp;\n}\nNK_LIB void*\nnk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type,\n    nk_size size, nk_size align)\n{\n    int full;\n    nk_size alignment;\n    void *unaligned;\n    void *memory;\n\n    NK_ASSERT(b);\n    NK_ASSERT(size);\n    if (!b || !size) return 0;\n    b->needed += size;\n\n    /* calculate total size with needed alignment + size */\n    if (type == NK_BUFFER_FRONT)\n        unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated);\n    else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size);\n    memory = nk_buffer_align(unaligned, align, &alignment, type);\n\n    /* check if buffer has enough memory*/\n    if (type == NK_BUFFER_FRONT)\n        full = ((b->allocated + size + alignment) > b->size);\n    else full = ((b->size - NK_MIN(b->size,(size + alignment))) <= b->allocated);\n\n    if (full) {\n        nk_size capacity;\n        if (b->type != NK_BUFFER_DYNAMIC)\n            return 0;\n        NK_ASSERT(b->pool.alloc && b->pool.free);\n        if (b->type != NK_BUFFER_DYNAMIC || !b->pool.alloc || !b->pool.free)\n            return 0;\n\n        /* buffer is full so allocate bigger buffer if dynamic */\n        capacity = (nk_size)((float)b->memory.size * b->grow_factor);\n        capacity = NK_MAX(capacity, nk_round_up_pow2((nk_uint)(b->allocated + size)));\n        b->memory.ptr = nk_buffer_realloc(b, capacity, &b->memory.size);\n        if (!b->memory.ptr) return 0;\n\n        /* align newly allocated pointer */\n        if (type == NK_BUFFER_FRONT)\n            unaligned = nk_ptr_add(void, b->memory.ptr, b->allocated);\n        else unaligned = nk_ptr_add(void, b->memory.ptr, b->size - size);\n        memory = nk_buffer_align(unaligned, align, &alignment, type);\n    }\n    if (type == NK_BUFFER_FRONT)\n        b->allocated += size + alignment;\n    else b->size -= (size + alignment);\n    b->needed += alignment;\n    b->calls++;\n    return memory;\n}\nNK_API void\nnk_buffer_push(struct nk_buffer *b, enum nk_buffer_allocation_type type,\n    const void *memory, nk_size size, nk_size align)\n{\n    void *mem = nk_buffer_alloc(b, type, size, align);\n    if (!mem) return;\n    NK_MEMCPY(mem, memory, size);\n}\nNK_API void\nnk_buffer_mark(struct nk_buffer *buffer, enum nk_buffer_allocation_type type)\n{\n    NK_ASSERT(buffer);\n    if (!buffer) return;\n    buffer->marker[type].active = nk_true;\n    if (type == NK_BUFFER_BACK)\n        buffer->marker[type].offset = buffer->size;\n    else buffer->marker[type].offset = buffer->allocated;\n}\nNK_API void\nnk_buffer_reset(struct nk_buffer *buffer, enum nk_buffer_allocation_type type)\n{\n    NK_ASSERT(buffer);\n    if (!buffer) return;\n    if (type == NK_BUFFER_BACK) {\n        /* reset back buffer either back to marker or empty */\n        buffer->needed -= (buffer->memory.size - buffer->marker[type].offset);\n        if (buffer->marker[type].active)\n            buffer->size = buffer->marker[type].offset;\n        else buffer->size = buffer->memory.size;\n        buffer->marker[type].active = nk_false;\n    } else {\n        /* reset front buffer either back to back marker or empty */\n        buffer->needed -= (buffer->allocated - buffer->marker[type].offset);\n        if (buffer->marker[type].active)\n            buffer->allocated = buffer->marker[type].offset;\n        else buffer->allocated = 0;\n        buffer->marker[type].active = nk_false;\n    }\n}\nNK_API void\nnk_buffer_clear(struct nk_buffer *b)\n{\n    NK_ASSERT(b);\n    if (!b) return;\n    b->allocated = 0;\n    b->size = b->memory.size;\n    b->calls = 0;\n    b->needed = 0;\n}\nNK_API void\nnk_buffer_free(struct nk_buffer *b)\n{\n    NK_ASSERT(b);\n    if (!b || !b->memory.ptr) return;\n    if (b->type == NK_BUFFER_FIXED) return;\n    if (!b->pool.free) return;\n    NK_ASSERT(b->pool.free);\n    b->pool.free(b->pool.userdata, b->memory.ptr);\n}\nNK_API void\nnk_buffer_info(struct nk_memory_status *s, const struct nk_buffer *b)\n{\n    NK_ASSERT(b);\n    NK_ASSERT(s);\n    if (!s || !b) return;\n    s->allocated = b->allocated;\n    s->size =  b->memory.size;\n    s->needed = b->needed;\n    s->memory = b->memory.ptr;\n    s->calls = b->calls;\n}\nNK_API void*\nnk_buffer_memory(struct nk_buffer *buffer)\n{\n    NK_ASSERT(buffer);\n    if (!buffer) return 0;\n    return buffer->memory.ptr;\n}\nNK_API const void*\nnk_buffer_memory_const(const struct nk_buffer *buffer)\n{\n    NK_ASSERT(buffer);\n    if (!buffer) return 0;\n    return buffer->memory.ptr;\n}\nNK_API nk_size\nnk_buffer_total(const struct nk_buffer *buffer)\n{\n    NK_ASSERT(buffer);\n    if (!buffer) return 0;\n    return buffer->memory.size;\n}\n"
  },
  {
    "path": "src/nuklear_button.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ==============================================================\n *\n *                          BUTTON\n *\n * ===============================================================*/\nNK_LIB void\nnk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type,\n    struct nk_rect content, struct nk_color background, struct nk_color foreground,\n    float border_width, const struct nk_user_font *font)\n{\n    switch (type) {\n    case NK_SYMBOL_X:\n    case NK_SYMBOL_UNDERSCORE:\n    case NK_SYMBOL_PLUS:\n    case NK_SYMBOL_MINUS: {\n        /* single character text symbol */\n        const char *X = (type == NK_SYMBOL_X) ? \"x\":\n            (type == NK_SYMBOL_UNDERSCORE) ? \"_\":\n            (type == NK_SYMBOL_PLUS) ? \"+\": \"-\";\n        struct nk_text text;\n        text.padding = nk_vec2(0,0);\n        text.background = background;\n        text.text = foreground;\n        nk_widget_text(out, content, X, 1, &text, NK_TEXT_CENTERED, font);\n    } break;\n    case NK_SYMBOL_CIRCLE_SOLID:\n    case NK_SYMBOL_CIRCLE_OUTLINE:\n    case NK_SYMBOL_RECT_SOLID:\n    case NK_SYMBOL_RECT_OUTLINE: {\n        /* simple empty/filled shapes */\n        if (type == NK_SYMBOL_RECT_SOLID || type == NK_SYMBOL_RECT_OUTLINE) {\n            nk_fill_rect(out, content,  0, foreground);\n            if (type == NK_SYMBOL_RECT_OUTLINE)\n                nk_fill_rect(out, nk_shrink_rect(content, border_width), 0, background);\n        } else {\n            nk_fill_circle(out, content, foreground);\n            if (type == NK_SYMBOL_CIRCLE_OUTLINE)\n                nk_fill_circle(out, nk_shrink_rect(content, 1), background);\n        }\n    } break;\n    case NK_SYMBOL_TRIANGLE_UP:\n    case NK_SYMBOL_TRIANGLE_DOWN:\n    case NK_SYMBOL_TRIANGLE_LEFT:\n    case NK_SYMBOL_TRIANGLE_RIGHT: {\n        enum nk_heading heading;\n        struct nk_vec2 points[3];\n        heading = (type == NK_SYMBOL_TRIANGLE_RIGHT) ? NK_RIGHT :\n            (type == NK_SYMBOL_TRIANGLE_LEFT) ? NK_LEFT:\n            (type == NK_SYMBOL_TRIANGLE_UP) ? NK_UP: NK_DOWN;\n        nk_triangle_from_direction(points, content, 0, 0, heading);\n        nk_fill_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y,\n            points[2].x, points[2].y, foreground);\n    } break;\n    case NK_SYMBOL_TRIANGLE_UP_OUTLINE:\n    case NK_SYMBOL_TRIANGLE_DOWN_OUTLINE:\n    case NK_SYMBOL_TRIANGLE_LEFT_OUTLINE:\n    case NK_SYMBOL_TRIANGLE_RIGHT_OUTLINE: {\n        enum nk_heading heading;\n        struct nk_vec2 points[3];\n        heading = (type == NK_SYMBOL_TRIANGLE_RIGHT_OUTLINE) ? NK_RIGHT :\n            (type == NK_SYMBOL_TRIANGLE_LEFT_OUTLINE) ? NK_LEFT:\n            (type == NK_SYMBOL_TRIANGLE_UP_OUTLINE) ? NK_UP: NK_DOWN;\n        nk_triangle_from_direction(points, content, 0, 0, heading);\n        nk_stroke_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y,\n            points[2].x, points[2].y, border_width, foreground);\n    } break;\n    default:\n    case NK_SYMBOL_NONE:\n    case NK_SYMBOL_MAX: break;\n    }\n}\nNK_LIB nk_bool\nnk_button_behavior(nk_flags *state, struct nk_rect r,\n    const struct nk_input *i, enum nk_button_behavior behavior)\n{\n    int ret = 0;\n    nk_widget_state_reset(state);\n    if (!i) return 0;\n    if (nk_input_is_mouse_hovering_rect(i, r)) {\n        *state = NK_WIDGET_STATE_HOVERED;\n        if (nk_input_is_mouse_down(i, NK_BUTTON_LEFT))\n            *state = NK_WIDGET_STATE_ACTIVE;\n        if (nk_input_has_mouse_click_in_button_rect(i, NK_BUTTON_LEFT, r)) {\n            ret = (behavior != NK_BUTTON_DEFAULT) ?\n                nk_input_is_mouse_down(i, NK_BUTTON_LEFT):\n#ifdef NK_BUTTON_TRIGGER_ON_RELEASE\n                nk_input_is_mouse_released(i, NK_BUTTON_LEFT);\n#else\n                nk_input_is_mouse_pressed(i, NK_BUTTON_LEFT);\n#endif\n        }\n    }\n    if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(i, r))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(i, r))\n        *state |= NK_WIDGET_STATE_LEFT;\n    return ret;\n}\nNK_LIB const struct nk_style_item*\nnk_draw_button(struct nk_command_buffer *out,\n    const struct nk_rect *bounds, nk_flags state,\n    const struct nk_style_button *style)\n{\n    const struct nk_style_item *background;\n    if (state & NK_WIDGET_STATE_HOVER)\n        background = &style->hover;\n    else if (state & NK_WIDGET_STATE_ACTIVED)\n        background = &style->active;\n    else background = &style->normal;\n\n    switch (background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor_background));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor_background));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor_background));\n            nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor_background));\n            break;\n    }\n    return background;\n}\nNK_LIB nk_bool\nnk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r,\n    const struct nk_style_button *style, const struct nk_input *in,\n    enum nk_button_behavior behavior, struct nk_rect *content)\n{\n    struct nk_rect bounds;\n    NK_ASSERT(style);\n    NK_ASSERT(state);\n    NK_ASSERT(out);\n    if (!out || !style)\n        return nk_false;\n\n    /* calculate button content space */\n    content->x = r.x + style->padding.x + style->border + style->rounding;\n    content->y = r.y + style->padding.y + style->border + style->rounding;\n    content->w = r.w - (2 * (style->padding.x + style->border + style->rounding));\n    content->h = r.h - (2 * (style->padding.y + style->border + style->rounding));\n\n    /* execute button behavior */\n    bounds.x = r.x - style->touch_padding.x;\n    bounds.y = r.y - style->touch_padding.y;\n    bounds.w = r.w + 2 * style->touch_padding.x;\n    bounds.h = r.h + 2 * style->touch_padding.y;\n    return nk_button_behavior(state, bounds, in, behavior);\n}\nNK_LIB void\nnk_draw_button_text(struct nk_command_buffer *out,\n    const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state,\n    const struct nk_style_button *style, const char *txt, int len,\n    nk_flags text_alignment, const struct nk_user_font *font)\n{\n    struct nk_text text;\n    const struct nk_style_item *background;\n    background = nk_draw_button(out, bounds, state, style);\n\n    /* select correct colors/images */\n    if (background->type == NK_STYLE_ITEM_COLOR)\n        text.background = background->data.color;\n    else text.background = style->text_background;\n    if (state & NK_WIDGET_STATE_HOVER)\n        text.text = style->text_hover;\n    else if (state & NK_WIDGET_STATE_ACTIVED)\n        text.text = style->text_active;\n    else text.text = style->text_normal;\n\n    text.text = nk_rgb_factor(text.text, style->color_factor_text);\n\n    text.padding = nk_vec2(0,0);\n    nk_widget_text(out, *content, txt, len, &text, text_alignment, font);\n}\nNK_LIB nk_bool\nnk_do_button_text(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    const char *string, int len, nk_flags align, enum nk_button_behavior behavior,\n    const struct nk_style_button *style, const struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    struct nk_rect content;\n    int ret = nk_false;\n\n    NK_ASSERT(state);\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    NK_ASSERT(string);\n    NK_ASSERT(font);\n    if (!out || !style || !font || !string)\n        return nk_false;\n\n    ret = nk_do_button(state, out, bounds, style, in, behavior, &content);\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_button_text(out, &bounds, &content, *state, style, string, len, align, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return ret;\n}\nNK_LIB void\nnk_draw_button_symbol(struct nk_command_buffer *out,\n    const struct nk_rect *bounds, const struct nk_rect *content,\n    nk_flags state, const struct nk_style_button *style,\n    enum nk_symbol_type type, const struct nk_user_font *font)\n{\n    struct nk_color sym, bg;\n    const struct nk_style_item *background;\n\n    /* select correct colors/images */\n    background = nk_draw_button(out, bounds, state, style);\n    if (background->type == NK_STYLE_ITEM_COLOR)\n        bg = background->data.color;\n    else bg = style->text_background;\n\n    if (state & NK_WIDGET_STATE_HOVER)\n        sym = style->text_hover;\n    else if (state & NK_WIDGET_STATE_ACTIVED)\n        sym = style->text_active;\n    else sym = style->text_normal;\n\n    sym = nk_rgb_factor(sym, style->color_factor_text);\n    nk_draw_symbol(out, type, *content, bg, sym, 1, font);\n}\nNK_LIB nk_bool\nnk_do_button_symbol(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    enum nk_symbol_type symbol, enum nk_button_behavior behavior,\n    const struct nk_style_button *style, const struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    int ret;\n    struct nk_rect content;\n\n    NK_ASSERT(state);\n    NK_ASSERT(style);\n    NK_ASSERT(font);\n    NK_ASSERT(out);\n    if (!out || !style || !font || !state)\n        return nk_false;\n\n    ret = nk_do_button(state, out, bounds, style, in, behavior, &content);\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_button_symbol(out, &bounds, &content, *state, style, symbol, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return ret;\n}\nNK_LIB void\nnk_draw_button_image(struct nk_command_buffer *out,\n    const struct nk_rect *bounds, const struct nk_rect *content,\n    nk_flags state, const struct nk_style_button *style, const struct nk_image *img)\n{\n    nk_draw_button(out, bounds, state, style);\n    nk_draw_image(out, *content, img, nk_rgb_factor(nk_white, style->color_factor_background));\n}\nNK_LIB nk_bool\nnk_do_button_image(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    struct nk_image img, enum nk_button_behavior b,\n    const struct nk_style_button *style, const struct nk_input *in)\n{\n    int ret;\n    struct nk_rect content;\n\n    NK_ASSERT(state);\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    if (!out || !style || !state)\n        return nk_false;\n\n    ret = nk_do_button(state, out, bounds, style, in, b, &content);\n    content.x += style->image_padding.x;\n    content.y += style->image_padding.y;\n    content.w -= 2 * style->image_padding.x;\n    content.h -= 2 * style->image_padding.y;\n\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_button_image(out, &bounds, &content, *state, style, &img);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return ret;\n}\nNK_LIB void\nnk_draw_button_text_symbol(struct nk_command_buffer *out,\n    const struct nk_rect *bounds, const struct nk_rect *label,\n    const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style,\n    const char *str, int len, enum nk_symbol_type type,\n    const struct nk_user_font *font)\n{\n    struct nk_color sym;\n    struct nk_text text;\n    const struct nk_style_item *background;\n\n    /* select correct background colors/images */\n    background = nk_draw_button(out, bounds, state, style);\n    if (background->type == NK_STYLE_ITEM_COLOR)\n        text.background = background->data.color;\n    else text.background = style->text_background;\n\n    /* select correct text colors */\n    if (state & NK_WIDGET_STATE_HOVER) {\n        sym = style->text_hover;\n        text.text = style->text_hover;\n    } else if (state & NK_WIDGET_STATE_ACTIVED) {\n        sym = style->text_active;\n        text.text = style->text_active;\n    } else {\n        sym = style->text_normal;\n        text.text = style->text_normal;\n    }\n\n    sym = nk_rgb_factor(sym, style->color_factor_text);\n    text.text = nk_rgb_factor(text.text, style->color_factor_text);\n    text.padding = nk_vec2(0,0);\n    nk_draw_symbol(out, type, *symbol, style->text_background, sym, 0, font);\n    nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font);\n}\nNK_LIB nk_bool\nnk_do_button_text_symbol(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    enum nk_symbol_type symbol, const char *str, int len, nk_flags align,\n    enum nk_button_behavior behavior, const struct nk_style_button *style,\n    const struct nk_user_font *font, const struct nk_input *in)\n{\n    int ret;\n    struct nk_rect tri = {0,0,0,0};\n    struct nk_rect content;\n\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    NK_ASSERT(font);\n    if (!out || !style || !font)\n        return nk_false;\n\n    ret = nk_do_button(state, out, bounds, style, in, behavior, &content);\n    tri.y = content.y + (content.h/2) - font->height/2;\n    tri.w = font->height; tri.h = font->height;\n    if (align & NK_TEXT_ALIGN_LEFT) {\n        tri.x = (content.x + content.w) - (2 * style->padding.x + tri.w);\n        tri.x = NK_MAX(tri.x, 0);\n    } else tri.x = content.x + 2 * style->padding.x;\n\n    /* draw button */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_button_text_symbol(out, &bounds, &content, &tri,\n        *state, style, str, len, symbol, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return ret;\n}\nNK_LIB void\nnk_draw_button_text_image(struct nk_command_buffer *out,\n    const struct nk_rect *bounds, const struct nk_rect *label,\n    const struct nk_rect *image, nk_flags state, const struct nk_style_button *style,\n    const char *str, int len, const struct nk_user_font *font,\n    const struct nk_image *img)\n{\n    struct nk_text text;\n    const struct nk_style_item *background;\n    background = nk_draw_button(out, bounds, state, style);\n\n    /* select correct colors */\n    if (background->type == NK_STYLE_ITEM_COLOR)\n        text.background = background->data.color;\n    else text.background = style->text_background;\n    if (state & NK_WIDGET_STATE_HOVER)\n        text.text = style->text_hover;\n    else if (state & NK_WIDGET_STATE_ACTIVED)\n        text.text = style->text_active;\n    else text.text = style->text_normal;\n\n    text.text = nk_rgb_factor(text.text, style->color_factor_text);\n    text.padding = nk_vec2(0, 0);\n    nk_widget_text(out, *label, str, len, &text, NK_TEXT_CENTERED, font);\n    nk_draw_image(out, *image, img, nk_rgb_factor(nk_white, style->color_factor_background));\n}\nNK_LIB nk_bool\nnk_do_button_text_image(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    struct nk_image img, const char* str, int len, nk_flags align,\n    enum nk_button_behavior behavior, const struct nk_style_button *style,\n    const struct nk_user_font *font, const struct nk_input *in)\n{\n    int ret;\n    struct nk_rect icon;\n    struct nk_rect content;\n\n    NK_ASSERT(style);\n    NK_ASSERT(state);\n    NK_ASSERT(font);\n    NK_ASSERT(out);\n    if (!out || !font || !style || !str)\n        return nk_false;\n\n    ret = nk_do_button(state, out, bounds, style, in, behavior, &content);\n    icon.y = bounds.y + style->padding.y;\n    icon.w = icon.h = bounds.h - 2 * style->padding.y;\n    if (align & NK_TEXT_ALIGN_LEFT) {\n        icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);\n        icon.x = NK_MAX(icon.x, 0);\n    } else icon.x = bounds.x + 2 * style->padding.x;\n\n    icon.x += style->image_padding.x;\n    icon.y += style->image_padding.y;\n    icon.w -= 2 * style->image_padding.x;\n    icon.h -= 2 * style->image_padding.y;\n\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_button_text_image(out, &bounds, &content, &icon, *state, style, str, len, font, &img);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return ret;\n}\nNK_API void\nnk_button_set_behavior(struct nk_context *ctx, enum nk_button_behavior behavior)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    ctx->button_behavior = behavior;\n}\nNK_API nk_bool\nnk_button_push_behavior(struct nk_context *ctx, enum nk_button_behavior behavior)\n{\n    struct nk_config_stack_button_behavior *button_stack;\n    struct nk_config_stack_button_behavior_element *element;\n\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n\n    button_stack = &ctx->stacks.button_behaviors;\n    NK_ASSERT(button_stack->head < (int)NK_LEN(button_stack->elements));\n    if (button_stack->head >= (int)NK_LEN(button_stack->elements))\n        return 0;\n\n    element = &button_stack->elements[button_stack->head++];\n    element->address = &ctx->button_behavior;\n    element->old_value = ctx->button_behavior;\n    ctx->button_behavior = behavior;\n    return 1;\n}\nNK_API nk_bool\nnk_button_pop_behavior(struct nk_context *ctx)\n{\n    struct nk_config_stack_button_behavior *button_stack;\n    struct nk_config_stack_button_behavior_element *element;\n\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n\n    button_stack = &ctx->stacks.button_behaviors;\n    NK_ASSERT(button_stack->head > 0);\n    if (button_stack->head < 1)\n        return 0;\n\n    element = &button_stack->elements[--button_stack->head];\n    *element->address = element->old_value;\n    return 1;\n}\nNK_API nk_bool\nnk_button_text_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, const char *title, int len)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(style);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!style || !ctx || !ctx->current || !ctx->current->layout) return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n    state = nk_widget(&bounds, ctx);\n\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,\n                    title, len, style->text_alignment, ctx->button_behavior,\n                    style, in, ctx->style.font);\n}\nNK_API nk_bool\nnk_button_text(struct nk_context *ctx, const char *title, int len)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    return nk_button_text_styled(ctx, &ctx->style.button, title, len);\n}\nNK_API nk_bool nk_button_label_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, const char *title)\n{\n    return nk_button_text_styled(ctx, style, title, nk_strlen(title));\n}\nNK_API nk_bool nk_button_label(struct nk_context *ctx, const char *title)\n{\n    return nk_button_text(ctx, title, nk_strlen(title));\n}\nNK_API nk_bool\nnk_button_color(struct nk_context *ctx, struct nk_color color)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    struct nk_style_button button;\n\n    int ret = 0;\n    struct nk_rect bounds;\n    struct nk_rect content;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n\n    button = ctx->style.button;\n    button.normal = nk_style_item_color(color);\n    button.hover = nk_style_item_color(color);\n    button.active = nk_style_item_color(color);\n    ret = nk_do_button(&ctx->last_widget_state, &win->buffer, bounds,\n                &button, in, ctx->button_behavior, &content);\n    nk_draw_button(&win->buffer, &bounds, ctx->last_widget_state, &button);\n    return ret;\n}\nNK_API nk_bool\nnk_button_symbol_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, enum nk_symbol_type symbol)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_button_symbol(&ctx->last_widget_state, &win->buffer, bounds,\n            symbol, ctx->button_behavior, style, in, ctx->style.font);\n}\nNK_API nk_bool\nnk_button_symbol(struct nk_context *ctx, enum nk_symbol_type symbol)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    return nk_button_symbol_styled(ctx, &ctx->style.button, symbol);\n}\nNK_API nk_bool\nnk_button_image_styled(struct nk_context *ctx, const struct nk_style_button *style,\n    struct nk_image img)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_button_image(&ctx->last_widget_state, &win->buffer, bounds,\n                img, ctx->button_behavior, style, in);\n}\nNK_API nk_bool\nnk_button_image(struct nk_context *ctx, struct nk_image img)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    return nk_button_image_styled(ctx, &ctx->style.button, img);\n}\nNK_API nk_bool\nnk_button_symbol_text_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, enum nk_symbol_type symbol,\n    const char *text, int len, nk_flags align)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,\n                symbol, text, len, align, ctx->button_behavior,\n                style, ctx->style.font, in);\n}\nNK_API nk_bool\nnk_button_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,\n    const char* text, int len, nk_flags align)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    return nk_button_symbol_text_styled(ctx, &ctx->style.button, symbol, text, len, align);\n}\nNK_API nk_bool nk_button_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,\n    const char *label, nk_flags align)\n{\n    return nk_button_symbol_text(ctx, symbol, label, nk_strlen(label), align);\n}\nNK_API nk_bool nk_button_symbol_label_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, enum nk_symbol_type symbol,\n    const char *title, nk_flags align)\n{\n    return nk_button_symbol_text_styled(ctx, style, symbol, title, nk_strlen(title), align);\n}\nNK_API nk_bool\nnk_button_image_text_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, struct nk_image img, const char *text,\n    int len, nk_flags align)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_button_text_image(&ctx->last_widget_state, &win->buffer,\n            bounds, img, text, len, align, ctx->button_behavior,\n            style, ctx->style.font, in);\n}\nNK_API nk_bool\nnk_button_image_text(struct nk_context *ctx, struct nk_image img,\n    const char *text, int len, nk_flags align)\n{\n    return nk_button_image_text_styled(ctx, &ctx->style.button,img, text, len, align);\n}\nNK_API nk_bool nk_button_image_label(struct nk_context *ctx, struct nk_image img,\n    const char *label, nk_flags align)\n{\n    return nk_button_image_text(ctx, img, label, nk_strlen(label), align);\n}\nNK_API nk_bool nk_button_image_label_styled(struct nk_context *ctx,\n    const struct nk_style_button *style, struct nk_image img,\n    const char *label, nk_flags text_alignment)\n{\n    return nk_button_image_text_styled(ctx, style, img, label, nk_strlen(label), text_alignment);\n}\n\n"
  },
  {
    "path": "src/nuklear_chart.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ==============================================================\n *\n *                          CHART\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_chart_begin_colored(struct nk_context *ctx, enum nk_chart_type type,\n    struct nk_color color, struct nk_color highlight,\n    int count, float min_value, float max_value)\n{\n    struct nk_window *win;\n    struct nk_chart *chart;\n    const struct nk_style *config;\n    const struct nk_style_chart *style;\n\n    const struct nk_style_item *background;\n    struct nk_rect bounds = {0, 0, 0, 0};\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n\n    if (!ctx || !ctx->current || !ctx->current->layout) return 0;\n    if (!nk_widget(&bounds, ctx)) {\n        chart = &ctx->current->layout->chart;\n        nk_zero(chart, sizeof(*chart));\n        return 0;\n    }\n\n    win = ctx->current;\n    config = &ctx->style;\n    chart = &win->layout->chart;\n    style = &config->chart;\n\n    /* setup basic generic chart  */\n    nk_zero(chart, sizeof(*chart));\n    chart->x = bounds.x + style->padding.x;\n    chart->y = bounds.y + style->padding.y;\n    chart->w = bounds.w - 2 * style->padding.x;\n    chart->h = bounds.h - 2 * style->padding.y;\n    chart->w = NK_MAX(chart->w, 2 * style->padding.x);\n    chart->h = NK_MAX(chart->h, 2 * style->padding.y);\n\n    /* add first slot into chart */\n    {struct nk_chart_slot *slot = &chart->slots[chart->slot++];\n    slot->type = type;\n    slot->count = count;\n    slot->color = nk_rgb_factor(color, style->color_factor);\n    slot->highlight = highlight;\n    slot->min = NK_MIN(min_value, max_value);\n    slot->max = NK_MAX(min_value, max_value);\n    slot->range = slot->max - slot->min;\n    slot->show_markers = style->show_markers;}\n\n    /* draw chart background */\n    background = &style->background;\n\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(&win->buffer, bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(&win->buffer, bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(&win->buffer, bounds, style->rounding, nk_rgb_factor(style->border_color, style->color_factor));\n            nk_fill_rect(&win->buffer, nk_shrink_rect(bounds, style->border),\n                style->rounding, nk_rgb_factor(style->background.data.color, style->color_factor));\n            break;\n    }\n    return 1;\n}\nNK_API nk_bool\nnk_chart_begin(struct nk_context *ctx, const enum nk_chart_type type,\n    int count, float min_value, float max_value)\n{\n    return nk_chart_begin_colored(ctx, type, ctx->style.chart.color,\n                ctx->style.chart.selected_color, count, min_value, max_value);\n}\nNK_API void\nnk_chart_add_slot_colored(struct nk_context *ctx, const enum nk_chart_type type,\n    struct nk_color color, struct nk_color highlight,\n    int count, float min_value, float max_value)\n{\n    const struct nk_style_chart* style;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    NK_ASSERT(ctx->current->layout->chart.slot < NK_CHART_MAX_SLOT);\n    if (!ctx || !ctx->current || !ctx->current->layout) return;\n    if (ctx->current->layout->chart.slot >= NK_CHART_MAX_SLOT) return;\n\n    style = &ctx->style.chart;\n\n    /* add another slot into the graph */\n    {struct nk_chart *chart = &ctx->current->layout->chart;\n    struct nk_chart_slot *slot = &chart->slots[chart->slot++];\n    slot->type = type;\n    slot->count = count;\n    slot->color = nk_rgb_factor(color, style->color_factor);\n    slot->highlight = highlight;\n    slot->min = NK_MIN(min_value, max_value);\n    slot->max = NK_MAX(min_value, max_value);\n    slot->range = slot->max - slot->min;\n    slot->show_markers = style->show_markers;}\n}\nNK_API void\nnk_chart_add_slot(struct nk_context *ctx, const enum nk_chart_type type,\n    int count, float min_value, float max_value)\n{\n    nk_chart_add_slot_colored(ctx, type, ctx->style.chart.color,\n        ctx->style.chart.selected_color, count, min_value, max_value);\n}\nNK_INTERN nk_flags\nnk_chart_push_line(struct nk_context *ctx, struct nk_window *win,\n    struct nk_chart *g, float value, int slot)\n{\n    struct nk_panel *layout = win->layout;\n    const struct nk_input *i = ctx->current->widgets_disabled ? 0 : &ctx->input;\n    struct nk_command_buffer *out = &win->buffer;\n\n    nk_flags ret = 0;\n    struct nk_vec2 cur;\n    struct nk_rect bounds;\n    struct nk_color color;\n    float step;\n    float range;\n    float ratio;\n\n    NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);\n    step = g->w / (float)g->slots[slot].count;\n    range = g->slots[slot].max - g->slots[slot].min;\n    ratio = (value - g->slots[slot].min) / range;\n\n    if (g->slots[slot].index == 0) {\n        /* first data point does not have a connection */\n        g->slots[slot].last.x = g->x;\n        g->slots[slot].last.y = (g->y + g->h) - ratio * (float)g->h;\n\n        bounds.x = g->slots[slot].last.x - 2;\n        bounds.y = g->slots[slot].last.y - 2;\n        bounds.w = bounds.h = 4;\n\n        color = g->slots[slot].color;\n        if (!(layout->flags & NK_WINDOW_ROM) && i &&\n            NK_INBOX(i->mouse.pos.x,i->mouse.pos.y, g->slots[slot].last.x-3, g->slots[slot].last.y-3, 6, 6)){\n            ret = nk_input_is_mouse_hovering_rect(i, bounds) ? NK_CHART_HOVERING : 0;\n            ret |= (i->mouse.buttons[NK_BUTTON_LEFT].down &&\n                i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;\n            color = g->slots[slot].highlight;\n        }\n        if (g->slots[slot].show_markers) {\n            nk_fill_rect(out, bounds, 0, color);\n        }\n        g->slots[slot].index += 1;\n        return ret;\n    }\n\n    /* draw a line between the last data point and the new one */\n    color = g->slots[slot].color;\n    cur.x = g->x + (float)(step * (float)g->slots[slot].index);\n    cur.y = (g->y + g->h) - (ratio * (float)g->h);\n    nk_stroke_line(out, g->slots[slot].last.x, g->slots[slot].last.y, cur.x, cur.y, 1.0f, color);\n\n    bounds.x = cur.x - 3;\n    bounds.y = cur.y - 3;\n    bounds.w = bounds.h = 6;\n\n    /* user selection of current data point */\n    if (!(layout->flags & NK_WINDOW_ROM)) {\n        if (nk_input_is_mouse_hovering_rect(i, bounds)) {\n            ret = NK_CHART_HOVERING;\n            ret |= (!i->mouse.buttons[NK_BUTTON_LEFT].down &&\n                i->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;\n            color = g->slots[slot].highlight;\n        }\n    }\n    if (g->slots[slot].show_markers) {\n        nk_fill_rect(out, nk_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color);\n    }\n\n    /* save current data point position */\n    g->slots[slot].last.x = cur.x;\n    g->slots[slot].last.y = cur.y;\n    g->slots[slot].index  += 1;\n    return ret;\n}\nNK_INTERN nk_flags\nnk_chart_push_column(const struct nk_context *ctx, struct nk_window *win,\n    struct nk_chart *chart, float value, int slot)\n{\n    struct nk_command_buffer *out = &win->buffer;\n    const struct nk_input *in = ctx->current->widgets_disabled ? 0 : &ctx->input;\n    struct nk_panel *layout = win->layout;\n\n    float ratio;\n    nk_flags ret = 0;\n    struct nk_color color;\n    struct nk_rect item = {0,0,0,0};\n\n    NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);\n    if (chart->slots[slot].index  >= chart->slots[slot].count)\n        return nk_false;\n    if (chart->slots[slot].count) {\n        float padding = (float)(chart->slots[slot].count-1);\n        item.w = (chart->w - padding) / (float)(chart->slots[slot].count);\n    }\n\n    /* calculate bounds of current bar chart entry */\n    color = chart->slots[slot].color;;\n    item.h = chart->h * NK_ABS((value/chart->slots[slot].range));\n    if (value >= 0) {\n        ratio = (value + NK_ABS(chart->slots[slot].min)) / NK_ABS(chart->slots[slot].range);\n        item.y = (chart->y + chart->h) - chart->h * ratio;\n    } else {\n        ratio = (value - chart->slots[slot].max) / chart->slots[slot].range;\n        item.y = chart->y + (chart->h * NK_ABS(ratio)) - item.h;\n    }\n    item.x = chart->x + ((float)chart->slots[slot].index * item.w);\n    item.x = item.x + ((float)chart->slots[slot].index);\n\n    /* user chart bar selection */\n    if (!(layout->flags & NK_WINDOW_ROM) && in &&\n        NK_INBOX(in->mouse.pos.x,in->mouse.pos.y,item.x,item.y,item.w,item.h)) {\n        ret = NK_CHART_HOVERING;\n        ret |= (!in->mouse.buttons[NK_BUTTON_LEFT].down &&\n                in->mouse.buttons[NK_BUTTON_LEFT].clicked) ? NK_CHART_CLICKED: 0;\n        color = chart->slots[slot].highlight;\n    }\n    nk_fill_rect(out, item, 0, color);\n    chart->slots[slot].index += 1;\n    return ret;\n}\nNK_API nk_flags\nnk_chart_push_slot(struct nk_context *ctx, float value, int slot)\n{\n    nk_flags flags;\n    struct nk_window *win;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(slot >= 0 && slot < NK_CHART_MAX_SLOT);\n    NK_ASSERT(slot < ctx->current->layout->chart.slot);\n    if (!ctx || !ctx->current || slot >= NK_CHART_MAX_SLOT) return nk_false;\n    if (slot >= ctx->current->layout->chart.slot) return nk_false;\n\n    win = ctx->current;\n    if (win->layout->chart.slot < slot) return nk_false;\n    switch (win->layout->chart.slots[slot].type) {\n    case NK_CHART_LINES:\n        flags = nk_chart_push_line(ctx, win, &win->layout->chart, value, slot); break;\n    case NK_CHART_COLUMN:\n        flags = nk_chart_push_column(ctx, win, &win->layout->chart, value, slot); break;\n    default:\n    case NK_CHART_MAX:\n        flags = 0;\n    }\n    return flags;\n}\nNK_API nk_flags\nnk_chart_push(struct nk_context *ctx, float value)\n{\n    return nk_chart_push_slot(ctx, value, 0);\n}\nNK_API void\nnk_chart_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_chart *chart;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return;\n\n    win = ctx->current;\n    chart = &win->layout->chart;\n    NK_MEMSET(chart, 0, sizeof(*chart));\n    return;\n}\nNK_API void\nnk_plot(struct nk_context *ctx, enum nk_chart_type type, const float *values,\n    int count, int offset)\n{\n    int i = 0;\n    float min_value;\n    float max_value;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(values);\n    if (!ctx || !values || !count) return;\n\n    min_value = values[offset];\n    max_value = values[offset];\n    for (i = 0; i < count; ++i) {\n        min_value = NK_MIN(values[i + offset], min_value);\n        max_value = NK_MAX(values[i + offset], max_value);\n    }\n\n    if (nk_chart_begin(ctx, type, count, min_value, max_value)) {\n        for (i = 0; i < count; ++i)\n            nk_chart_push(ctx, values[i + offset]);\n        nk_chart_end(ctx);\n    }\n}\nNK_API void\nnk_plot_function(struct nk_context *ctx, enum nk_chart_type type, void *userdata,\n    float(*value_getter)(void* user, int index), int count, int offset)\n{\n    int i = 0;\n    float min_value;\n    float max_value;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(value_getter);\n    if (!ctx || !value_getter || !count) return;\n\n    max_value = min_value = value_getter(userdata, offset);\n    for (i = 0; i < count; ++i) {\n        float value = value_getter(userdata, i + offset);\n        min_value = NK_MIN(value, min_value);\n        max_value = NK_MAX(value, max_value);\n    }\n\n    if (nk_chart_begin(ctx, type, count, min_value, max_value)) {\n        for (i = 0; i < count; ++i)\n            nk_chart_push(ctx, value_getter(userdata, i + offset));\n        nk_chart_end(ctx);\n    }\n}\n\n"
  },
  {
    "path": "src/nuklear_color.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ==============================================================\n *\n *                          COLOR\n *\n * ===============================================================*/\nNK_INTERN int\nnk_parse_hex(const char *p, int length)\n{\n    int i = 0;\n    int len = 0;\n    while (len < length) {\n        i <<= 4;\n        if (p[len] >= 'a' && p[len] <= 'f')\n            i += ((p[len] - 'a') + 10);\n        else if (p[len] >= 'A' && p[len] <= 'F')\n            i += ((p[len] - 'A') + 10);\n        else i += (p[len] - '0');\n        len++;\n    }\n    return i;\n}\nNK_API struct nk_color\nnk_rgb_factor(struct nk_color col, float factor)\n{\n    if (factor == 1.0f)\n        return col;\n    col.r = (nk_byte)(col.r * factor);\n    col.g = (nk_byte)(col.g * factor);\n    col.b = (nk_byte)(col.b * factor);\n    return col;\n}\nNK_API struct nk_color\nnk_rgba(int r, int g, int b, int a)\n{\n    struct nk_color ret;\n    ret.r = (nk_byte)NK_CLAMP(0, r, 255);\n    ret.g = (nk_byte)NK_CLAMP(0, g, 255);\n    ret.b = (nk_byte)NK_CLAMP(0, b, 255);\n    ret.a = (nk_byte)NK_CLAMP(0, a, 255);\n    return ret;\n}\nNK_API struct nk_color\nnk_rgb_hex(const char *rgb)\n{\n    struct nk_color col;\n    const char *c = rgb;\n    if (*c == '#') c++;\n    col.r = (nk_byte)nk_parse_hex(c, 2);\n    col.g = (nk_byte)nk_parse_hex(c+2, 2);\n    col.b = (nk_byte)nk_parse_hex(c+4, 2);\n    col.a = 255;\n    return col;\n}\nNK_API struct nk_color\nnk_rgba_hex(const char *rgb)\n{\n    struct nk_color col;\n    const char *c = rgb;\n    if (*c == '#') c++;\n    col.r = (nk_byte)nk_parse_hex(c, 2);\n    col.g = (nk_byte)nk_parse_hex(c+2, 2);\n    col.b = (nk_byte)nk_parse_hex(c+4, 2);\n    col.a = (nk_byte)nk_parse_hex(c+6, 2);\n    return col;\n}\nNK_API void\nnk_color_hex_rgba(char *output, struct nk_color col)\n{\n    #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i))\n    output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);\n    output[1] = (char)NK_TO_HEX((col.r & 0x0F));\n    output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);\n    output[3] = (char)NK_TO_HEX((col.g & 0x0F));\n    output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);\n    output[5] = (char)NK_TO_HEX((col.b & 0x0F));\n    output[6] = (char)NK_TO_HEX((col.a & 0xF0) >> 4);\n    output[7] = (char)NK_TO_HEX((col.a & 0x0F));\n    output[8] = '\\0';\n    #undef NK_TO_HEX\n}\nNK_API void\nnk_color_hex_rgb(char *output, struct nk_color col)\n{\n    #define NK_TO_HEX(i) ((i) <= 9 ? '0' + (i): 'A' - 10 + (i))\n    output[0] = (char)NK_TO_HEX((col.r & 0xF0) >> 4);\n    output[1] = (char)NK_TO_HEX((col.r & 0x0F));\n    output[2] = (char)NK_TO_HEX((col.g & 0xF0) >> 4);\n    output[3] = (char)NK_TO_HEX((col.g & 0x0F));\n    output[4] = (char)NK_TO_HEX((col.b & 0xF0) >> 4);\n    output[5] = (char)NK_TO_HEX((col.b & 0x0F));\n    output[6] = '\\0';\n    #undef NK_TO_HEX\n}\nNK_API struct nk_color\nnk_rgba_iv(const int *c)\n{\n    return nk_rgba(c[0], c[1], c[2], c[3]);\n}\nNK_API struct nk_color\nnk_rgba_bv(const nk_byte *c)\n{\n    return nk_rgba(c[0], c[1], c[2], c[3]);\n}\nNK_API struct nk_color\nnk_rgb(int r, int g, int b)\n{\n    struct nk_color ret;\n    ret.r = (nk_byte)NK_CLAMP(0, r, 255);\n    ret.g = (nk_byte)NK_CLAMP(0, g, 255);\n    ret.b = (nk_byte)NK_CLAMP(0, b, 255);\n    ret.a = (nk_byte)255;\n    return ret;\n}\nNK_API struct nk_color\nnk_rgb_iv(const int *c)\n{\n    return nk_rgb(c[0], c[1], c[2]);\n}\nNK_API struct nk_color\nnk_rgb_bv(const nk_byte* c)\n{\n    return nk_rgb(c[0], c[1], c[2]);\n}\nNK_API struct nk_color\nnk_rgba_u32(nk_uint in)\n{\n    struct nk_color ret;\n    ret.r = (in & 0xFF);\n    ret.g = ((in >> 8) & 0xFF);\n    ret.b = ((in >> 16) & 0xFF);\n    ret.a = (nk_byte)((in >> 24) & 0xFF);\n    return ret;\n}\nNK_API struct nk_color\nnk_rgba_f(float r, float g, float b, float a)\n{\n    struct nk_color ret;\n    ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);\n    ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);\n    ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);\n    ret.a = (nk_byte)(NK_SATURATE(a) * 255.0f);\n    return ret;\n}\nNK_API struct nk_color\nnk_rgba_fv(const float *c)\n{\n    return nk_rgba_f(c[0], c[1], c[2], c[3]);\n}\nNK_API struct nk_color\nnk_rgba_cf(struct nk_colorf c)\n{\n    return nk_rgba_f(c.r, c.g, c.b, c.a);\n}\nNK_API struct nk_color\nnk_rgb_f(float r, float g, float b)\n{\n    struct nk_color ret;\n    ret.r = (nk_byte)(NK_SATURATE(r) * 255.0f);\n    ret.g = (nk_byte)(NK_SATURATE(g) * 255.0f);\n    ret.b = (nk_byte)(NK_SATURATE(b) * 255.0f);\n    ret.a = 255;\n    return ret;\n}\nNK_API struct nk_color\nnk_rgb_fv(const float *c)\n{\n    return nk_rgb_f(c[0], c[1], c[2]);\n}\nNK_API struct nk_color\nnk_rgb_cf(struct nk_colorf c)\n{\n    return nk_rgb_f(c.r, c.g, c.b);\n}\nNK_API struct nk_color\nnk_hsv(int h, int s, int v)\n{\n    return nk_hsva(h, s, v, 255);\n}\nNK_API struct nk_color\nnk_hsv_iv(const int *c)\n{\n    return nk_hsv(c[0], c[1], c[2]);\n}\nNK_API struct nk_color\nnk_hsv_bv(const nk_byte *c)\n{\n    return nk_hsv(c[0], c[1], c[2]);\n}\nNK_API struct nk_color\nnk_hsv_f(float h, float s, float v)\n{\n    return nk_hsva_f(h, s, v, 1.0f);\n}\nNK_API struct nk_color\nnk_hsv_fv(const float *c)\n{\n    return nk_hsv_f(c[0], c[1], c[2]);\n}\nNK_API struct nk_color\nnk_hsva(int h, int s, int v, int a)\n{\n    float hf = ((float)NK_CLAMP(0, h, 255)) / 255.0f;\n    float sf = ((float)NK_CLAMP(0, s, 255)) / 255.0f;\n    float vf = ((float)NK_CLAMP(0, v, 255)) / 255.0f;\n    float af = ((float)NK_CLAMP(0, a, 255)) / 255.0f;\n    return nk_hsva_f(hf, sf, vf, af);\n}\nNK_API struct nk_color\nnk_hsva_iv(const int *c)\n{\n    return nk_hsva(c[0], c[1], c[2], c[3]);\n}\nNK_API struct nk_color\nnk_hsva_bv(const nk_byte *c)\n{\n    return nk_hsva(c[0], c[1], c[2], c[3]);\n}\nNK_API struct nk_colorf\nnk_hsva_colorf(float h, float s, float v, float a)\n{\n    int i;\n    float p, q, t, f;\n    struct nk_colorf out = {0,0,0,0};\n    if (s <= 0.0f) {\n        out.r = v; out.g = v; out.b = v; out.a = a;\n        return out;\n    }\n    h = h / (60.0f/360.0f);\n    i = (int)h;\n    f = h - (float)i;\n    p = v * (1.0f - s);\n    q = v * (1.0f - (s * f));\n    t = v * (1.0f - s * (1.0f - f));\n\n    switch (i) {\n    case 0: default: out.r = v; out.g = t; out.b = p; break;\n    case 1: out.r = q; out.g = v; out.b = p; break;\n    case 2: out.r = p; out.g = v; out.b = t; break;\n    case 3: out.r = p; out.g = q; out.b = v; break;\n    case 4: out.r = t; out.g = p; out.b = v; break;\n    case 5: out.r = v; out.g = p; out.b = q; break;}\n    out.a = a;\n    return out;\n}\nNK_API struct nk_colorf\nnk_hsva_colorfv(const float *c)\n{\n    return nk_hsva_colorf(c[0], c[1], c[2], c[3]);\n}\nNK_API struct nk_color\nnk_hsva_f(float h, float s, float v, float a)\n{\n    struct nk_colorf c = nk_hsva_colorf(h, s, v, a);\n    return nk_rgba_f(c.r, c.g, c.b, c.a);\n}\nNK_API struct nk_color\nnk_hsva_fv(const float *c)\n{\n    return nk_hsva_f(c[0], c[1], c[2], c[3]);\n}\nNK_API nk_uint\nnk_color_u32(struct nk_color in)\n{\n    nk_uint out = (nk_uint)in.r;\n    out |= ((nk_uint)in.g << 8);\n    out |= ((nk_uint)in.b << 16);\n    out |= ((nk_uint)in.a << 24);\n    return out;\n}\nNK_API void\nnk_color_f(float *r, float *g, float *b, float *a, struct nk_color in)\n{\n    NK_STORAGE const float s = 1.0f/255.0f;\n    *r = (float)in.r * s;\n    *g = (float)in.g * s;\n    *b = (float)in.b * s;\n    *a = (float)in.a * s;\n}\nNK_API void\nnk_color_fv(float *c, struct nk_color in)\n{\n    nk_color_f(&c[0], &c[1], &c[2], &c[3], in);\n}\nNK_API struct nk_colorf\nnk_color_cf(struct nk_color in)\n{\n    struct nk_colorf o;\n    nk_color_f(&o.r, &o.g, &o.b, &o.a, in);\n    return o;\n}\nNK_API void\nnk_color_d(double *r, double *g, double *b, double *a, struct nk_color in)\n{\n    NK_STORAGE const double s = 1.0/255.0;\n    *r = (double)in.r * s;\n    *g = (double)in.g * s;\n    *b = (double)in.b * s;\n    *a = (double)in.a * s;\n}\nNK_API void\nnk_color_dv(double *c, struct nk_color in)\n{\n    nk_color_d(&c[0], &c[1], &c[2], &c[3], in);\n}\nNK_API void\nnk_color_hsv_f(float *out_h, float *out_s, float *out_v, struct nk_color in)\n{\n    float a;\n    nk_color_hsva_f(out_h, out_s, out_v, &a, in);\n}\nNK_API void\nnk_color_hsv_fv(float *out, struct nk_color in)\n{\n    float a;\n    nk_color_hsva_f(&out[0], &out[1], &out[2], &a, in);\n}\nNK_API void\nnk_colorf_hsva_f(float *out_h, float *out_s,\n    float *out_v, float *out_a, struct nk_colorf in)\n{\n    float chroma;\n    float K = 0.0f;\n    if (in.g < in.b) {\n        const float t = in.g; in.g = in.b; in.b = t;\n        K = -1.f;\n    }\n    if (in.r < in.g) {\n        const float t = in.r; in.r = in.g; in.g = t;\n        K = -2.f/6.0f - K;\n    }\n    chroma = in.r - ((in.g < in.b) ? in.g: in.b);\n    *out_h = NK_ABS(K + (in.g - in.b)/(6.0f * chroma + 1e-20f));\n    *out_s = chroma / (in.r + 1e-20f);\n    *out_v = in.r;\n    *out_a = in.a;\n\n}\nNK_API void\nnk_colorf_hsva_fv(float *hsva, struct nk_colorf in)\n{\n    nk_colorf_hsva_f(&hsva[0], &hsva[1], &hsva[2], &hsva[3], in);\n}\nNK_API void\nnk_color_hsva_f(float *out_h, float *out_s,\n    float *out_v, float *out_a, struct nk_color in)\n{\n    struct nk_colorf col;\n    nk_color_f(&col.r,&col.g,&col.b,&col.a, in);\n    nk_colorf_hsva_f(out_h, out_s, out_v, out_a, col);\n}\nNK_API void\nnk_color_hsva_fv(float *out, struct nk_color in)\n{\n    nk_color_hsva_f(&out[0], &out[1], &out[2], &out[3], in);\n}\nNK_API void\nnk_color_hsva_i(int *out_h, int *out_s, int *out_v,\n                int *out_a, struct nk_color in)\n{\n    float h,s,v,a;\n    nk_color_hsva_f(&h, &s, &v, &a, in);\n    *out_h = (nk_byte)(h * 255.0f);\n    *out_s = (nk_byte)(s * 255.0f);\n    *out_v = (nk_byte)(v * 255.0f);\n    *out_a = (nk_byte)(a * 255.0f);\n}\nNK_API void\nnk_color_hsva_iv(int *out, struct nk_color in)\n{\n    nk_color_hsva_i(&out[0], &out[1], &out[2], &out[3], in);\n}\nNK_API void\nnk_color_hsva_bv(nk_byte *out, struct nk_color in)\n{\n    int tmp[4];\n    nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);\n    out[0] = (nk_byte)tmp[0];\n    out[1] = (nk_byte)tmp[1];\n    out[2] = (nk_byte)tmp[2];\n    out[3] = (nk_byte)tmp[3];\n}\nNK_API void\nnk_color_hsva_b(nk_byte *h, nk_byte *s, nk_byte *v, nk_byte *a, struct nk_color in)\n{\n    int tmp[4];\n    nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);\n    *h = (nk_byte)tmp[0];\n    *s = (nk_byte)tmp[1];\n    *v = (nk_byte)tmp[2];\n    *a = (nk_byte)tmp[3];\n}\nNK_API void\nnk_color_hsv_i(int *out_h, int *out_s, int *out_v, struct nk_color in)\n{\n    int a;\n    nk_color_hsva_i(out_h, out_s, out_v, &a, in);\n}\nNK_API void\nnk_color_hsv_b(nk_byte *out_h, nk_byte *out_s, nk_byte *out_v, struct nk_color in)\n{\n    int tmp[4];\n    nk_color_hsva_i(&tmp[0], &tmp[1], &tmp[2], &tmp[3], in);\n    *out_h = (nk_byte)tmp[0];\n    *out_s = (nk_byte)tmp[1];\n    *out_v = (nk_byte)tmp[2];\n}\nNK_API void\nnk_color_hsv_iv(int *out, struct nk_color in)\n{\n    nk_color_hsv_i(&out[0], &out[1], &out[2], in);\n}\nNK_API void\nnk_color_hsv_bv(nk_byte *out, struct nk_color in)\n{\n    int tmp[4];\n    nk_color_hsv_i(&tmp[0], &tmp[1], &tmp[2], in);\n    out[0] = (nk_byte)tmp[0];\n    out[1] = (nk_byte)tmp[1];\n    out[2] = (nk_byte)tmp[2];\n}\n"
  },
  {
    "path": "src/nuklear_color_picker.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ==============================================================\n *\n *                          COLOR PICKER\n *\n * ===============================================================*/\nNK_LIB nk_bool\nnk_color_picker_behavior(nk_flags *state,\n    const struct nk_rect *bounds, const struct nk_rect *matrix,\n    const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar,\n    struct nk_colorf *color, const struct nk_input *in)\n{\n    float hsva[4];\n    nk_bool value_changed = 0;\n    nk_bool hsv_changed = 0;\n\n    NK_ASSERT(state);\n    NK_ASSERT(matrix);\n    NK_ASSERT(hue_bar);\n    NK_ASSERT(color);\n\n    /* color matrix */\n    nk_colorf_hsva_fv(hsva, *color);\n    if (nk_button_behavior(state, *matrix, in, NK_BUTTON_REPEATER)) {\n        hsva[1] = NK_SATURATE((in->mouse.pos.x - matrix->x) / (matrix->w-1));\n        hsva[2] = 1.0f - NK_SATURATE((in->mouse.pos.y - matrix->y) / (matrix->h-1));\n        value_changed = hsv_changed = 1;\n    }\n    /* hue bar */\n    if (nk_button_behavior(state, *hue_bar, in, NK_BUTTON_REPEATER)) {\n        hsva[0] = NK_SATURATE((in->mouse.pos.y - hue_bar->y) / (hue_bar->h-1));\n        value_changed = hsv_changed = 1;\n    }\n    /* alpha bar */\n    if (alpha_bar) {\n        if (nk_button_behavior(state, *alpha_bar, in, NK_BUTTON_REPEATER)) {\n            hsva[3] = 1.0f - NK_SATURATE((in->mouse.pos.y - alpha_bar->y) / (alpha_bar->h-1));\n            value_changed = 1;\n        }\n    }\n    nk_widget_state_reset(state);\n    if (hsv_changed) {\n        *color = nk_hsva_colorfv(hsva);\n        *state = NK_WIDGET_STATE_ACTIVE;\n    }\n    if (value_changed) {\n        color->a = hsva[3];\n        *state = NK_WIDGET_STATE_ACTIVE;\n    }\n    /* set color picker widget state */\n    if (nk_input_is_mouse_hovering_rect(in, *bounds))\n        *state = NK_WIDGET_STATE_HOVERED;\n    if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *bounds))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, *bounds))\n        *state |= NK_WIDGET_STATE_LEFT;\n    return value_changed;\n}\nNK_LIB void\nnk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix,\n    const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar,\n    struct nk_colorf col)\n{\n    NK_STORAGE const struct nk_color black = {0,0,0,255};\n    NK_STORAGE const struct nk_color white = {255, 255, 255, 255};\n    NK_STORAGE const struct nk_color black_trans = {0,0,0,0};\n\n    const float crosshair_size = 7.0f;\n    struct nk_color temp;\n    float hsva[4];\n    float line_y;\n    int i;\n\n    NK_ASSERT(o);\n    NK_ASSERT(matrix);\n    NK_ASSERT(hue_bar);\n\n    /* draw hue bar */\n    nk_colorf_hsva_fv(hsva, col);\n    for (i = 0; i < 6; ++i) {\n        NK_GLOBAL const struct nk_color hue_colors[] = {\n            {255, 0, 0, 255}, {255,255,0,255}, {0,255,0,255}, {0, 255,255,255},\n            {0,0,255,255}, {255, 0, 255, 255}, {255, 0, 0, 255}\n        };\n        nk_fill_rect_multi_color(o,\n            nk_rect(hue_bar->x, hue_bar->y + (float)i * (hue_bar->h/6.0f) + 0.5f,\n                hue_bar->w, (hue_bar->h/6.0f) + 0.5f), hue_colors[i], hue_colors[i],\n                hue_colors[i+1], hue_colors[i+1]);\n    }\n    line_y = (float)(int)(hue_bar->y + hsva[0] * matrix->h + 0.5f);\n    nk_stroke_line(o, hue_bar->x-1, line_y, hue_bar->x + hue_bar->w + 2,\n        line_y, 1, nk_rgb(255,255,255));\n\n    /* draw alpha bar */\n    if (alpha_bar) {\n        float alpha = NK_SATURATE(col.a);\n        line_y = (float)(int)(alpha_bar->y +  (1.0f - alpha) * matrix->h + 0.5f);\n\n        nk_fill_rect_multi_color(o, *alpha_bar, white, white, black, black);\n        nk_stroke_line(o, alpha_bar->x-1, line_y, alpha_bar->x + alpha_bar->w + 2,\n            line_y, 1, nk_rgb(255,255,255));\n    }\n\n    /* draw color matrix */\n    temp = nk_hsv_f(hsva[0], 1.0f, 1.0f);\n    nk_fill_rect_multi_color(o, *matrix, white, temp, temp, white);\n    nk_fill_rect_multi_color(o, *matrix, black_trans, black_trans, black, black);\n\n    /* draw cross-hair */\n    {struct nk_vec2 p; float S = hsva[1]; float V = hsva[2];\n    p.x = (float)(int)(matrix->x + S * matrix->w);\n    p.y = (float)(int)(matrix->y + (1.0f - V) * matrix->h);\n    nk_stroke_line(o, p.x - crosshair_size, p.y, p.x-2, p.y, 1.0f, white);\n    nk_stroke_line(o, p.x + crosshair_size + 1, p.y, p.x+3, p.y, 1.0f, white);\n    nk_stroke_line(o, p.x, p.y + crosshair_size + 1, p.x, p.y+3, 1.0f, white);\n    nk_stroke_line(o, p.x, p.y - crosshair_size, p.x, p.y-2, 1.0f, white);}\n}\nNK_LIB nk_bool\nnk_do_color_picker(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_colorf *col,\n    enum nk_color_format fmt, struct nk_rect bounds,\n    struct nk_vec2 padding, const struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    int ret = 0;\n    struct nk_rect matrix;\n    struct nk_rect hue_bar;\n    struct nk_rect alpha_bar;\n    float bar_w;\n\n    NK_ASSERT(out);\n    NK_ASSERT(col);\n    NK_ASSERT(state);\n    NK_ASSERT(font);\n    if (!out || !col || !state || !font)\n        return ret;\n\n    bar_w = font->height;\n    bounds.x += padding.x;\n    bounds.y += padding.x;\n    bounds.w -= 2 * padding.x;\n    bounds.h -= 2 * padding.y;\n\n    matrix.x = bounds.x;\n    matrix.y = bounds.y;\n    matrix.h = bounds.h;\n    matrix.w = bounds.w - (3 * padding.x + 2 * bar_w);\n\n    hue_bar.w = bar_w;\n    hue_bar.y = bounds.y;\n    hue_bar.h = matrix.h;\n    hue_bar.x = matrix.x + matrix.w + padding.x;\n\n    alpha_bar.x = hue_bar.x + hue_bar.w + padding.x;\n    alpha_bar.y = bounds.y;\n    alpha_bar.w = bar_w;\n    alpha_bar.h = matrix.h;\n\n    ret = nk_color_picker_behavior(state, &bounds, &matrix, &hue_bar,\n        (fmt == NK_RGBA) ? &alpha_bar:0, col, in);\n    nk_draw_color_picker(out, &matrix, &hue_bar, (fmt == NK_RGBA) ? &alpha_bar:0, *col);\n    return ret;\n}\nNK_API nk_bool\nnk_color_pick(struct nk_context * ctx, struct nk_colorf *color,\n    enum nk_color_format fmt)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_style *config;\n    const struct nk_input *in;\n\n    enum nk_widget_layout_states state;\n    struct nk_rect bounds;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(color);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !color)\n        return 0;\n\n    win = ctx->current;\n    config = &ctx->style;\n    layout = win->layout;\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_color_picker(&ctx->last_widget_state, &win->buffer, color, fmt, bounds,\n                nk_vec2(0,0), in, config->font);\n}\nNK_API struct nk_colorf\nnk_color_picker(struct nk_context *ctx, struct nk_colorf color,\n    enum nk_color_format fmt)\n{\n    nk_color_pick(ctx, &color, fmt);\n    return color;\n}\n\n"
  },
  {
    "path": "src/nuklear_combo.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ==============================================================\n *\n *                          COMBO\n *\n * ===============================================================*/\nNK_INTERN nk_bool\nnk_combo_begin(struct nk_context *ctx, struct nk_window *win,\n    struct nk_vec2 size, nk_bool is_clicked, struct nk_rect header)\n{\n    struct nk_window *popup;\n    int is_open = 0;\n    int is_active = 0;\n    struct nk_rect body;\n    nk_hash hash;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    popup = win->popup.win;\n    body.x = header.x;\n    body.w = size.x;\n    body.y = header.y + header.h-ctx->style.window.combo_border;\n    body.h = size.y;\n\n    hash = win->popup.combo_count++;\n    is_open = (popup) ? nk_true:nk_false;\n    is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_COMBO);\n    if ((is_clicked && is_open && !is_active) || (is_open && !is_active) ||\n        (!is_open && !is_active && !is_clicked)) return 0;\n    if (!nk_nonblock_begin(ctx, 0, body,\n        (is_clicked && is_open)?nk_rect(0,0,0,0):header, NK_PANEL_COMBO)) return 0;\n\n    win->popup.type = NK_PANEL_COMBO;\n    win->popup.name = hash;\n    return 1;\n}\nNK_API nk_bool\nnk_combo_begin_text(struct nk_context *ctx, const char *selected, int len,\n    struct nk_vec2 size)\n{\n    const struct nk_input *in;\n    struct nk_window *win;\n    struct nk_style *style;\n\n    enum nk_widget_layout_states s;\n    int is_clicked = nk_false;\n    struct nk_rect header;\n    const struct nk_style_item *background;\n    struct nk_text text;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(selected);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !selected)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    s = nk_widget(&header, ctx);\n    if (s == NK_WIDGET_INVALID)\n        return 0;\n\n    in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;\n    if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))\n        is_clicked = nk_true;\n\n    /* draw combo box header background and border */\n    if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->combo.active;\n        text.text = style->combo.label_active;\n    } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {\n        background = &style->combo.hover;\n        text.text = style->combo.label_hover;\n    } else {\n        background = &style->combo.normal;\n        text.text = style->combo.label_normal;\n    }\n\n    text.text = nk_rgb_factor(text.text, style->combo.color_factor);\n\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            text.background = background->data.color;\n            nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));\n            nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));\n            break;\n    }\n    {\n        /* print currently selected text item */\n        struct nk_rect label;\n        struct nk_rect button;\n        struct nk_rect content;\n        int draw_button_symbol;\n\n        enum nk_symbol_type sym;\n        if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n            sym = style->combo.sym_hover;\n        else if (is_clicked)\n            sym = style->combo.sym_active;\n        else\n            sym = style->combo.sym_normal;\n\n        /* represents whether or not the combo's button symbol should be drawn */\n        draw_button_symbol = sym != NK_SYMBOL_NONE;\n\n        /* calculate button */\n        button.w = header.h - 2 * style->combo.button_padding.y;\n        button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;\n        button.y = header.y + style->combo.button_padding.y;\n        button.h = button.w;\n\n        content.x = button.x + style->combo.button.padding.x;\n        content.y = button.y + style->combo.button.padding.y;\n        content.w = button.w - 2 * style->combo.button.padding.x;\n        content.h = button.h - 2 * style->combo.button.padding.y;\n\n        /* draw selected label */\n        text.padding = nk_vec2(0,0);\n        label.x = header.x + style->combo.content_padding.x;\n        label.y = header.y + style->combo.content_padding.y;\n        label.h = header.h - 2 * style->combo.content_padding.y;\n        if (draw_button_symbol)\n            label.w = button.x - (style->combo.content_padding.x + style->combo.spacing.x) - label.x;\n        else\n            label.w = header.w - 2 * style->combo.content_padding.x;\n        nk_widget_text(&win->buffer, label, selected, len, &text,\n            NK_TEXT_LEFT, ctx->style.font);\n\n        /* draw open/close button */\n        if (draw_button_symbol)\n            nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,\n                &ctx->style.combo.button, sym, style->font);\n    }\n    return nk_combo_begin(ctx, win, size, is_clicked, header);\n}\nNK_API nk_bool\nnk_combo_begin_label(struct nk_context *ctx, const char *selected, struct nk_vec2 size)\n{\n    return nk_combo_begin_text(ctx, selected, nk_strlen(selected), size);\n}\nNK_API nk_bool\nnk_combo_begin_color(struct nk_context *ctx, struct nk_color color, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    const struct nk_input *in;\n\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    enum nk_widget_layout_states s;\n    const struct nk_style_item *background;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    s = nk_widget(&header, ctx);\n    if (s == NK_WIDGET_INVALID)\n        return 0;\n\n    in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;\n    if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))\n        is_clicked = nk_true;\n\n    /* draw combo box header background and border */\n    if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED)\n        background = &style->combo.active;\n    else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n        background = &style->combo.hover;\n    else background = &style->combo.normal;\n\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));\n            nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));\n            break;\n    }\n    {\n        struct nk_rect content;\n        struct nk_rect button;\n        struct nk_rect bounds;\n        int draw_button_symbol;\n\n        enum nk_symbol_type sym;\n        if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n            sym = style->combo.sym_hover;\n        else if (is_clicked)\n            sym = style->combo.sym_active;\n        else sym = style->combo.sym_normal;\n\n        /* represents whether or not the combo's button symbol should be drawn */\n        draw_button_symbol = sym != NK_SYMBOL_NONE;\n\n        /* calculate button */\n        button.w = header.h - 2 * style->combo.button_padding.y;\n        button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;\n        button.y = header.y + style->combo.button_padding.y;\n        button.h = button.w;\n\n        content.x = button.x + style->combo.button.padding.x;\n        content.y = button.y + style->combo.button.padding.y;\n        content.w = button.w - 2 * style->combo.button.padding.x;\n        content.h = button.h - 2 * style->combo.button.padding.y;\n\n        /* draw color */\n        bounds.h = header.h - 4 * style->combo.content_padding.y;\n        bounds.y = header.y + 2 * style->combo.content_padding.y;\n        bounds.x = header.x + 2 * style->combo.content_padding.x;\n        if (draw_button_symbol)\n            bounds.w = (button.x - (style->combo.content_padding.x + style->combo.spacing.x)) - bounds.x;\n        else\n            bounds.w = header.w - 4 * style->combo.content_padding.x;\n        nk_fill_rect(&win->buffer, bounds, 0, nk_rgb_factor(color, style->combo.color_factor));\n\n        /* draw open/close button */\n        if (draw_button_symbol)\n            nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,\n                &ctx->style.combo.button, sym, style->font);\n    }\n    return nk_combo_begin(ctx, win, size, is_clicked, header);\n}\nNK_API nk_bool\nnk_combo_begin_symbol(struct nk_context *ctx, enum nk_symbol_type symbol, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    const struct nk_input *in;\n\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    enum nk_widget_layout_states s;\n    const struct nk_style_item *background;\n    struct nk_color sym_background;\n    struct nk_color symbol_color;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    s = nk_widget(&header, ctx);\n    if (s == NK_WIDGET_INVALID)\n        return 0;\n\n    in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;\n    if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))\n        is_clicked = nk_true;\n\n    /* draw combo box header background and border */\n    if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->combo.active;\n        symbol_color = style->combo.symbol_active;\n    } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {\n        background = &style->combo.hover;\n        symbol_color = style->combo.symbol_hover;\n    } else {\n        background = &style->combo.normal;\n        symbol_color = style->combo.symbol_hover;\n    }\n\n    symbol_color = nk_rgb_factor(symbol_color, style->combo.color_factor);\n\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            sym_background = nk_rgba(0, 0, 0, 0);\n            nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            sym_background = nk_rgba(0, 0, 0, 0);\n            nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            sym_background = background->data.color;\n            nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));\n            nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));\n            break;\n    }\n    {\n        struct nk_rect bounds = {0,0,0,0};\n        struct nk_rect content;\n        struct nk_rect button;\n\n        enum nk_symbol_type sym;\n        if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n            sym = style->combo.sym_hover;\n        else if (is_clicked)\n            sym = style->combo.sym_active;\n        else sym = style->combo.sym_normal;\n\n        /* calculate button */\n        button.w = header.h - 2 * style->combo.button_padding.y;\n        button.x = (header.x + header.w - header.h) - style->combo.button_padding.y;\n        button.y = header.y + style->combo.button_padding.y;\n        button.h = button.w;\n\n        content.x = button.x + style->combo.button.padding.x;\n        content.y = button.y + style->combo.button.padding.y;\n        content.w = button.w - 2 * style->combo.button.padding.x;\n        content.h = button.h - 2 * style->combo.button.padding.y;\n\n        /* draw symbol */\n        bounds.h = header.h - 2 * style->combo.content_padding.y;\n        bounds.y = header.y + style->combo.content_padding.y;\n        bounds.x = header.x + style->combo.content_padding.x;\n        bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;\n        nk_draw_symbol(&win->buffer, symbol, bounds, sym_background, symbol_color,\n            1.0f, style->font);\n\n        /* draw open/close button */\n        nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state,\n            &ctx->style.combo.button, sym, style->font);\n    }\n    return nk_combo_begin(ctx, win, size, is_clicked, header);\n}\nNK_API nk_bool\nnk_combo_begin_symbol_text(struct nk_context *ctx, const char *selected, int len,\n    enum nk_symbol_type symbol, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    struct nk_input *in;\n\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    enum nk_widget_layout_states s;\n    const struct nk_style_item *background;\n    struct nk_color symbol_color;\n    struct nk_text text;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    s = nk_widget(&header, ctx);\n    if (!s) return 0;\n\n    in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;\n    if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))\n        is_clicked = nk_true;\n\n    /* draw combo box header background and border */\n    if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->combo.active;\n        symbol_color = style->combo.symbol_active;\n        text.text = style->combo.label_active;\n    } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {\n        background = &style->combo.hover;\n        symbol_color = style->combo.symbol_hover;\n        text.text = style->combo.label_hover;\n    } else {\n        background = &style->combo.normal;\n        symbol_color = style->combo.symbol_normal;\n        text.text = style->combo.label_normal;\n    }\n\n    text.text = nk_rgb_factor(text.text, style->combo.color_factor);\n    symbol_color = nk_rgb_factor(symbol_color, style->combo.color_factor);\n\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            text.background = background->data.color;\n            nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));\n            nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));\n            break;\n    }\n    {\n        struct nk_rect content;\n        struct nk_rect button;\n        struct nk_rect label;\n        struct nk_rect image;\n\n        enum nk_symbol_type sym;\n        if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n            sym = style->combo.sym_hover;\n        else if (is_clicked)\n            sym = style->combo.sym_active;\n        else sym = style->combo.sym_normal;\n\n        /* calculate button */\n        button.w = header.h - 2 * style->combo.button_padding.y;\n        button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;\n        button.y = header.y + style->combo.button_padding.y;\n        button.h = button.w;\n\n        content.x = button.x + style->combo.button.padding.x;\n        content.y = button.y + style->combo.button.padding.y;\n        content.w = button.w - 2 * style->combo.button.padding.x;\n        content.h = button.h - 2 * style->combo.button.padding.y;\n        nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,\n            &ctx->style.combo.button, sym, style->font);\n\n        /* draw symbol */\n        image.x = header.x + style->combo.content_padding.x;\n        image.y = header.y + style->combo.content_padding.y;\n        image.h = header.h - 2 * style->combo.content_padding.y;\n        image.w = image.h;\n        nk_draw_symbol(&win->buffer, symbol, image, text.background, symbol_color,\n            1.0f, style->font);\n\n        /* draw label */\n        text.padding = nk_vec2(0,0);\n        label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x;\n        label.y = header.y + style->combo.content_padding.y;\n        label.w = (button.x - style->combo.content_padding.x) - label.x;\n        label.h = header.h - 2 * style->combo.content_padding.y;\n        nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font);\n    }\n    return nk_combo_begin(ctx, win, size, is_clicked, header);\n}\nNK_API nk_bool\nnk_combo_begin_image(struct nk_context *ctx, struct nk_image img, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    const struct nk_input *in;\n\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    enum nk_widget_layout_states s;\n    const struct nk_style_item *background;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    s = nk_widget(&header, ctx);\n    if (s == NK_WIDGET_INVALID)\n        return 0;\n\n    in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;\n    if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))\n        is_clicked = nk_true;\n\n    /* draw combo box header background and border */\n    if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED)\n        background = &style->combo.active;\n    else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n        background = &style->combo.hover;\n    else background = &style->combo.normal;\n\n    switch (background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));\n            nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));\n            break;\n    }\n    {\n        struct nk_rect bounds = {0,0,0,0};\n        struct nk_rect content;\n        struct nk_rect button;\n        int draw_button_symbol;\n\n        enum nk_symbol_type sym;\n        if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n            sym = style->combo.sym_hover;\n        else if (is_clicked)\n            sym = style->combo.sym_active;\n        else sym = style->combo.sym_normal;\n\n        /* represents whether or not the combo's button symbol should be drawn */\n        draw_button_symbol = sym != NK_SYMBOL_NONE;\n\n        /* calculate button */\n        button.w = header.h - 2 * style->combo.button_padding.y;\n        button.x = (header.x + header.w - header.h) - style->combo.button_padding.y;\n        button.y = header.y + style->combo.button_padding.y;\n        button.h = button.w;\n\n        content.x = button.x + style->combo.button.padding.x;\n        content.y = button.y + style->combo.button.padding.y;\n        content.w = button.w - 2 * style->combo.button.padding.x;\n        content.h = button.h - 2 * style->combo.button.padding.y;\n\n        /* draw image */\n        bounds.h = header.h - 2 * style->combo.content_padding.y;\n        bounds.y = header.y + style->combo.content_padding.y;\n        bounds.x = header.x + style->combo.content_padding.x;\n        if (draw_button_symbol)\n            bounds.w = (button.x - style->combo.content_padding.y) - bounds.x;\n        else\n            bounds.w = header.w - 2 * style->combo.content_padding.x;\n        nk_draw_image(&win->buffer, bounds, &img, nk_rgb_factor(nk_white, style->combo.color_factor));\n\n        /* draw open/close button */\n        if (draw_button_symbol)\n            nk_draw_button_symbol(&win->buffer, &bounds, &content, ctx->last_widget_state,\n                &ctx->style.combo.button, sym, style->font);\n    }\n    return nk_combo_begin(ctx, win, size, is_clicked, header);\n}\nNK_API nk_bool\nnk_combo_begin_image_text(struct nk_context *ctx, const char *selected, int len,\n    struct nk_image img, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    struct nk_input *in;\n\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    enum nk_widget_layout_states s;\n    const struct nk_style_item *background;\n    struct nk_text text;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    s = nk_widget(&header, ctx);\n    if (!s) return 0;\n\n    in = (win->layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED || s == NK_WIDGET_ROM)? 0: &ctx->input;\n    if (nk_button_behavior(&ctx->last_widget_state, header, in, NK_BUTTON_DEFAULT))\n        is_clicked = nk_true;\n\n    /* draw combo box header background and border */\n    if (ctx->last_widget_state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->combo.active;\n        text.text = style->combo.label_active;\n    } else if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER) {\n        background = &style->combo.hover;\n        text.text = style->combo.label_hover;\n    } else {\n        background = &style->combo.normal;\n        text.text = style->combo.label_normal;\n    }\n\n    text.text = nk_rgb_factor(text.text, style->combo.color_factor);\n\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_image(&win->buffer, header, &background->data.image, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_rgb_factor(nk_white, style->combo.color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            text.background = background->data.color;\n            nk_fill_rect(&win->buffer, header, style->combo.rounding, nk_rgb_factor(background->data.color, style->combo.color_factor));\n            nk_stroke_rect(&win->buffer, header, style->combo.rounding, style->combo.border, nk_rgb_factor(style->combo.border_color, style->combo.color_factor));\n            break;\n    }\n    {\n        struct nk_rect content;\n        struct nk_rect button;\n        struct nk_rect label;\n        struct nk_rect image;\n        int draw_button_symbol;\n\n        enum nk_symbol_type sym;\n        if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n            sym = style->combo.sym_hover;\n        else if (is_clicked)\n            sym = style->combo.sym_active;\n        else sym = style->combo.sym_normal;\n\n        /* represents whether or not the combo's button symbol should be drawn */\n        draw_button_symbol = sym != NK_SYMBOL_NONE;\n\n        /* calculate button */\n        button.w = header.h - 2 * style->combo.button_padding.y;\n        button.x = (header.x + header.w - header.h) - style->combo.button_padding.x;\n        button.y = header.y + style->combo.button_padding.y;\n        button.h = button.w;\n\n        content.x = button.x + style->combo.button.padding.x;\n        content.y = button.y + style->combo.button.padding.y;\n        content.w = button.w - 2 * style->combo.button.padding.x;\n        content.h = button.h - 2 * style->combo.button.padding.y;\n        if (draw_button_symbol)\n            nk_draw_button_symbol(&win->buffer, &button, &content, ctx->last_widget_state,\n                &ctx->style.combo.button, sym, style->font);\n\n        /* draw image */\n        image.x = header.x + style->combo.content_padding.x;\n        image.y = header.y + style->combo.content_padding.y;\n        image.h = header.h - 2 * style->combo.content_padding.y;\n        image.w = image.h;\n        nk_draw_image(&win->buffer, image, &img, nk_rgb_factor(nk_white, style->combo.color_factor));\n\n        /* draw label */\n        text.padding = nk_vec2(0,0);\n        label.x = image.x + image.w + style->combo.spacing.x + style->combo.content_padding.x;\n        label.y = header.y + style->combo.content_padding.y;\n        label.h = header.h - 2 * style->combo.content_padding.y;\n        if (draw_button_symbol)\n            label.w = (button.x - style->combo.content_padding.x) - label.x;\n        else\n            label.w = (header.x + header.w - style->combo.content_padding.x) - label.x;\n        nk_widget_text(&win->buffer, label, selected, len, &text, NK_TEXT_LEFT, style->font);\n    }\n    return nk_combo_begin(ctx, win, size, is_clicked, header);\n}\nNK_API nk_bool\nnk_combo_begin_symbol_label(struct nk_context *ctx,\n    const char *selected, enum nk_symbol_type type, struct nk_vec2 size)\n{\n    return nk_combo_begin_symbol_text(ctx, selected, nk_strlen(selected), type, size);\n}\nNK_API nk_bool\nnk_combo_begin_image_label(struct nk_context *ctx,\n    const char *selected, struct nk_image img, struct nk_vec2 size)\n{\n    return nk_combo_begin_image_text(ctx, selected, nk_strlen(selected), img, size);\n}\nNK_API nk_bool\nnk_combo_item_text(struct nk_context *ctx, const char *text, int len,nk_flags align)\n{\n    return nk_contextual_item_text(ctx, text, len, align);\n}\nNK_API nk_bool\nnk_combo_item_label(struct nk_context *ctx, const char *label, nk_flags align)\n{\n    return nk_contextual_item_label(ctx, label, align);\n}\nNK_API nk_bool\nnk_combo_item_image_text(struct nk_context *ctx, struct nk_image img, const char *text,\n    int len, nk_flags alignment)\n{\n    return nk_contextual_item_image_text(ctx, img, text, len, alignment);\n}\nNK_API nk_bool\nnk_combo_item_image_label(struct nk_context *ctx, struct nk_image img,\n    const char *text, nk_flags alignment)\n{\n    return nk_contextual_item_image_label(ctx, img, text, alignment);\n}\nNK_API nk_bool\nnk_combo_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *text, int len, nk_flags alignment)\n{\n    return nk_contextual_item_symbol_text(ctx, sym, text, len, alignment);\n}\nNK_API nk_bool\nnk_combo_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *label, nk_flags alignment)\n{\n    return nk_contextual_item_symbol_label(ctx, sym, label, alignment);\n}\nNK_API void nk_combo_end(struct nk_context *ctx)\n{\n    nk_contextual_end(ctx);\n}\nNK_API void nk_combo_close(struct nk_context *ctx)\n{\n    nk_contextual_close(ctx);\n}\nNK_API int\nnk_combo(struct nk_context *ctx, const char *const *items, int count,\n    int selected, int item_height, struct nk_vec2 size)\n{\n    int i = 0;\n    int max_height;\n    struct nk_vec2 item_spacing;\n    struct nk_vec2 window_padding;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(items);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !items ||!count)\n        return selected;\n\n    item_spacing = ctx->style.window.spacing;\n    window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);\n    max_height = count * item_height + count * (int)item_spacing.y;\n    max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;\n    size.y = NK_MIN(size.y, (float)max_height);\n    if (nk_combo_begin_label(ctx, items[selected], size)) {\n        nk_layout_row_dynamic(ctx, (float)item_height, 1);\n        for (i = 0; i < count; ++i) {\n            if (nk_combo_item_label(ctx, items[i], NK_TEXT_LEFT))\n                selected = i;\n        }\n        nk_combo_end(ctx);\n    }\n    return selected;\n}\nNK_API int\nnk_combo_separator(struct nk_context *ctx, const char *items_separated_by_separator,\n    int separator, int selected, int count, int item_height, struct nk_vec2 size)\n{\n    int i;\n    int max_height;\n    struct nk_vec2 item_spacing;\n    struct nk_vec2 window_padding;\n    const char *current_item;\n    const char *iter;\n    int length = 0;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(items_separated_by_separator);\n    if (!ctx || !items_separated_by_separator)\n        return selected;\n\n    /* calculate popup window */\n    item_spacing = ctx->style.window.spacing;\n    window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);\n    max_height = count * item_height + count * (int)item_spacing.y;\n    max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;\n    size.y = NK_MIN(size.y, (float)max_height);\n\n    /* find selected item */\n    current_item = items_separated_by_separator;\n    for (i = 0; i < count; ++i) {\n        iter = current_item;\n        while (*iter && *iter != separator) iter++;\n        length = (int)(iter - current_item);\n        if (i == selected) break;\n        current_item = iter + 1;\n    }\n\n    if (nk_combo_begin_text(ctx, current_item, length, size)) {\n        current_item = items_separated_by_separator;\n        nk_layout_row_dynamic(ctx, (float)item_height, 1);\n        for (i = 0; i < count; ++i) {\n            iter = current_item;\n            while (*iter && *iter != separator) iter++;\n            length = (int)(iter - current_item);\n            if (nk_combo_item_text(ctx, current_item, length, NK_TEXT_LEFT))\n                selected = i;\n            current_item = current_item + length + 1;\n        }\n        nk_combo_end(ctx);\n    }\n    return selected;\n}\nNK_API int\nnk_combo_string(struct nk_context *ctx, const char *items_separated_by_zeros,\n    int selected, int count, int item_height, struct nk_vec2 size)\n{\n    return nk_combo_separator(ctx, items_separated_by_zeros, '\\0', selected, count, item_height, size);\n}\nNK_API int\nnk_combo_callback(struct nk_context *ctx, void(*item_getter)(void*, int, const char**),\n    void *userdata, int selected, int count, int item_height, struct nk_vec2 size)\n{\n    int i;\n    int max_height;\n    struct nk_vec2 item_spacing;\n    struct nk_vec2 window_padding;\n    const char *item;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(item_getter);\n    if (!ctx || !item_getter)\n        return selected;\n\n    /* calculate popup window */\n    item_spacing = ctx->style.window.spacing;\n    window_padding = nk_panel_get_padding(&ctx->style, ctx->current->layout->type);\n    max_height = count * item_height + count * (int)item_spacing.y;\n    max_height += (int)item_spacing.y * 2 + (int)window_padding.y * 2;\n    size.y = NK_MIN(size.y, (float)max_height);\n\n    item_getter(userdata, selected, &item);\n    if (nk_combo_begin_label(ctx, item, size)) {\n        nk_layout_row_dynamic(ctx, (float)item_height, 1);\n        for (i = 0; i < count; ++i) {\n            item_getter(userdata, i, &item);\n            if (nk_combo_item_label(ctx, item, NK_TEXT_LEFT))\n                selected = i;\n        }\n        nk_combo_end(ctx);\n    } return selected;\n}\nNK_API nk_bool\nnk_combobox(struct nk_context *ctx, const char *const *items, int count,\n    int *selected, int item_height, struct nk_vec2 size)\n{\n    int tmp = *selected;\n    *selected = nk_combo(ctx, items, count, *selected, item_height, size);\n    return tmp != *selected;\n}\nNK_API nk_bool\nnk_combobox_string(struct nk_context *ctx, const char *items_separated_by_zeros,\n    int *selected, int count, int item_height, struct nk_vec2 size)\n{\n    int tmp = *selected;\n    *selected = nk_combo_string(ctx, items_separated_by_zeros, *selected, count, item_height, size);\n    return tmp != *selected;\n}\nNK_API nk_bool\nnk_combobox_separator(struct nk_context *ctx, const char *items_separated_by_separator,\n    int separator, int *selected, int count, int item_height, struct nk_vec2 size)\n{\n    int tmp = *selected;\n    *selected = nk_combo_separator(ctx, items_separated_by_separator, separator,\n                                    *selected, count, item_height, size);\n    return tmp != *selected;\n}\nNK_API nk_bool\nnk_combobox_callback(struct nk_context *ctx,\n    void(*item_getter)(void* data, int id, const char **out_text),\n    void *userdata, int *selected, int count, int item_height, struct nk_vec2 size)\n{\n    int tmp = *selected;\n    *selected = nk_combo_callback(ctx, item_getter, userdata,  *selected, count, item_height, size);\n    return tmp != *selected;\n}\n"
  },
  {
    "path": "src/nuklear_context.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ==============================================================\n *\n *                          CONTEXT\n *\n * ===============================================================*/\nNK_INTERN void\nnk_setup(struct nk_context *ctx, const struct nk_user_font *font)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    nk_zero_struct(*ctx);\n    nk_style_default(ctx);\n    ctx->seq = 1;\n    if (font) ctx->style.font = font;\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n    nk_draw_list_init(&ctx->draw_list);\n#endif\n}\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API nk_bool\nnk_init_default(struct nk_context *ctx, const struct nk_user_font *font)\n{\n    struct nk_allocator alloc;\n    alloc.userdata.ptr = 0;\n    alloc.alloc = nk_malloc;\n    alloc.free = nk_mfree;\n    return nk_init(ctx, &alloc, font);\n}\n#endif\nNK_API nk_bool\nnk_init_fixed(struct nk_context *ctx, void *memory, nk_size size,\n    const struct nk_user_font *font)\n{\n    NK_ASSERT(memory);\n    if (!memory) return 0;\n    nk_setup(ctx, font);\n    nk_buffer_init_fixed(&ctx->memory, memory, size);\n    ctx->use_pool = nk_false;\n    return 1;\n}\nNK_API nk_bool\nnk_init_custom(struct nk_context *ctx, struct nk_buffer *cmds,\n    struct nk_buffer *pool, const struct nk_user_font *font)\n{\n    NK_ASSERT(cmds);\n    NK_ASSERT(pool);\n    if (!cmds || !pool) return 0;\n\n    nk_setup(ctx, font);\n    ctx->memory = *cmds;\n    if (pool->type == NK_BUFFER_FIXED) {\n        /* take memory from buffer and alloc fixed pool */\n        nk_pool_init_fixed(&ctx->pool, pool->memory.ptr, pool->memory.size);\n    } else {\n        /* create dynamic pool from buffer allocator */\n        struct nk_allocator *alloc = &pool->pool;\n        nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);\n    }\n    ctx->use_pool = nk_true;\n    return 1;\n}\nNK_API nk_bool\nnk_init(struct nk_context *ctx, const struct nk_allocator *alloc,\n    const struct nk_user_font *font)\n{\n    NK_ASSERT(alloc);\n    if (!alloc) return 0;\n    nk_setup(ctx, font);\n    nk_buffer_init(&ctx->memory, alloc, NK_DEFAULT_COMMAND_BUFFER_SIZE);\n    nk_pool_init(&ctx->pool, alloc, NK_POOL_DEFAULT_CAPACITY);\n    ctx->use_pool = nk_true;\n    return 1;\n}\n#ifdef NK_INCLUDE_COMMAND_USERDATA\nNK_API void\nnk_set_user_data(struct nk_context *ctx, nk_handle handle)\n{\n    if (!ctx) return;\n    ctx->userdata = handle;\n    if (ctx->current)\n        ctx->current->buffer.userdata = handle;\n}\n#endif\nNK_API void\nnk_free(struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    nk_buffer_free(&ctx->memory);\n    if (ctx->use_pool)\n        nk_pool_free(&ctx->pool);\n\n    nk_zero(&ctx->input, sizeof(ctx->input));\n    nk_zero(&ctx->style, sizeof(ctx->style));\n    nk_zero(&ctx->memory, sizeof(ctx->memory));\n\n    ctx->seq = 0;\n    ctx->build = 0;\n    ctx->begin = 0;\n    ctx->end = 0;\n    ctx->active = 0;\n    ctx->current = 0;\n    ctx->freelist = 0;\n    ctx->count = 0;\n}\nNK_API void\nnk_clear(struct nk_context *ctx)\n{\n    struct nk_window *iter;\n    struct nk_window *next;\n    NK_ASSERT(ctx);\n\n    if (!ctx) return;\n    if (ctx->use_pool)\n        nk_buffer_clear(&ctx->memory);\n    else nk_buffer_reset(&ctx->memory, NK_BUFFER_FRONT);\n\n    ctx->build = 0;\n    ctx->memory.calls = 0;\n    ctx->last_widget_state = 0;\n    ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];\n    NK_MEMSET(&ctx->overlay, 0, sizeof(ctx->overlay));\n\n    /* garbage collector */\n    iter = ctx->begin;\n    while (iter) {\n        /* make sure valid minimized windows do not get removed */\n        if ((iter->flags & NK_WINDOW_MINIMIZED) &&\n            !(iter->flags & NK_WINDOW_CLOSED) &&\n            iter->seq == ctx->seq) {\n            iter = iter->next;\n            continue;\n        }\n        /* remove hotness from hidden or closed windows*/\n        if (((iter->flags & NK_WINDOW_HIDDEN) ||\n            (iter->flags & NK_WINDOW_CLOSED)) &&\n            iter == ctx->active) {\n            ctx->active = iter->prev;\n            ctx->end = iter->prev;\n            if (!ctx->end)\n                ctx->begin = 0;\n            if (ctx->active)\n                ctx->active->flags &= ~(unsigned)NK_WINDOW_ROM;\n        }\n        /* free unused popup windows */\n        if (iter->popup.win && iter->popup.win->seq != ctx->seq) {\n            nk_free_window(ctx, iter->popup.win);\n            iter->popup.win = 0;\n        }\n        /* remove unused window state tables */\n        {struct nk_table *n, *it = iter->tables;\n        while (it) {\n            n = it->next;\n            if (it->seq != ctx->seq) {\n                nk_remove_table(iter, it);\n                nk_zero(it, sizeof(union nk_page_data));\n                nk_free_table(ctx, it);\n                if (it == iter->tables)\n                    iter->tables = n;\n            } it = n;\n        }}\n        /* window itself is not used anymore so free */\n        if (iter->seq != ctx->seq || iter->flags & NK_WINDOW_CLOSED) {\n            next = iter->next;\n            nk_remove_window(ctx, iter);\n            nk_free_window(ctx, iter);\n            iter = next;\n        } else iter = iter->next;\n    }\n    ctx->seq++;\n}\nNK_LIB void\nnk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(buffer);\n    if (!ctx || !buffer) return;\n    buffer->begin = ctx->memory.allocated;\n    buffer->end = buffer->begin;\n    buffer->last = buffer->begin;\n    buffer->clip = nk_null_rect;\n}\nNK_LIB void\nnk_start(struct nk_context *ctx, struct nk_window *win)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(win);\n    nk_start_buffer(ctx, &win->buffer);\n}\nNK_LIB void\nnk_start_popup(struct nk_context *ctx, struct nk_window *win)\n{\n    struct nk_popup_buffer *buf;\n    NK_ASSERT(ctx);\n    NK_ASSERT(win);\n    if (!ctx || !win) return;\n\n    /* save buffer fill state for popup */\n    buf = &win->popup.buf;\n    buf->begin = win->buffer.end;\n    buf->end = win->buffer.end;\n    buf->parent = win->buffer.last;\n    buf->last = buf->begin;\n    buf->active = nk_true;\n}\nNK_LIB void\nnk_finish_popup(struct nk_context *ctx, struct nk_window *win)\n{\n    struct nk_popup_buffer *buf;\n    NK_ASSERT(ctx);\n    NK_ASSERT(win);\n    if (!ctx || !win) return;\n\n    buf = &win->popup.buf;\n    buf->last = win->buffer.last;\n    buf->end = win->buffer.end;\n}\nNK_LIB void\nnk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *buffer)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(buffer);\n    if (!ctx || !buffer) return;\n    buffer->end = ctx->memory.allocated;\n}\nNK_LIB void\nnk_finish(struct nk_context *ctx, struct nk_window *win)\n{\n    struct nk_popup_buffer *buf;\n    struct nk_command *parent_last;\n    void *memory;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(win);\n    if (!ctx || !win) return;\n    nk_finish_buffer(ctx, &win->buffer);\n    if (!win->popup.buf.active) return;\n\n    buf = &win->popup.buf;\n    memory = ctx->memory.memory.ptr;\n    parent_last = nk_ptr_add(struct nk_command, memory, buf->parent);\n    parent_last->next = buf->end;\n}\nNK_LIB void\nnk_build(struct nk_context *ctx)\n{\n    struct nk_window *it = 0;\n    struct nk_command *cmd = 0;\n    nk_byte *buffer = 0;\n\n    /* draw cursor overlay */\n    if (!ctx->style.cursor_active)\n        ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_ARROW];\n    if (ctx->style.cursor_active && !ctx->input.mouse.grabbed && ctx->style.cursor_visible) {\n        struct nk_rect mouse_bounds;\n        const struct nk_cursor *cursor = ctx->style.cursor_active;\n        nk_command_buffer_init(&ctx->overlay, &ctx->memory, NK_CLIPPING_OFF);\n        nk_start_buffer(ctx, &ctx->overlay);\n\n        mouse_bounds.x = ctx->input.mouse.pos.x - cursor->offset.x;\n        mouse_bounds.y = ctx->input.mouse.pos.y - cursor->offset.y;\n        mouse_bounds.w = cursor->size.x;\n        mouse_bounds.h = cursor->size.y;\n\n        nk_draw_image(&ctx->overlay, mouse_bounds, &cursor->img, nk_white);\n        nk_finish_buffer(ctx, &ctx->overlay);\n    }\n    /* build one big draw command list out of all window buffers */\n    it = ctx->begin;\n    buffer = (nk_byte*)ctx->memory.memory.ptr;\n    while (it != 0) {\n        struct nk_window *next = it->next;\n        if (it->buffer.last == it->buffer.begin || (it->flags & NK_WINDOW_HIDDEN)||\n            it->seq != ctx->seq)\n            goto cont;\n\n        cmd = nk_ptr_add(struct nk_command, buffer, it->buffer.last);\n        while (next && ((next->buffer.last == next->buffer.begin) ||\n            (next->flags & NK_WINDOW_HIDDEN) || next->seq != ctx->seq))\n            next = next->next; /* skip empty command buffers */\n\n        if (next) cmd->next = next->buffer.begin;\n        cont: it = next;\n    }\n    /* append all popup draw commands into lists */\n    it = ctx->begin;\n    while (it != 0) {\n        struct nk_window *next = it->next;\n        struct nk_popup_buffer *buf;\n        if (!it->popup.buf.active)\n            goto skip;\n\n        buf = &it->popup.buf;\n        cmd->next = buf->begin;\n        cmd = nk_ptr_add(struct nk_command, buffer, buf->last);\n        buf->active = nk_false;\n        skip: it = next;\n    }\n    if (cmd) {\n        /* append overlay commands */\n        if (ctx->overlay.end != ctx->overlay.begin)\n            cmd->next = ctx->overlay.begin;\n        else cmd->next = ctx->memory.allocated;\n    }\n}\nNK_API const struct nk_command*\nnk__begin(struct nk_context *ctx)\n{\n    struct nk_window *iter;\n    nk_byte *buffer;\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    if (!ctx->count) return 0;\n\n    buffer = (nk_byte*)ctx->memory.memory.ptr;\n    if (!ctx->build) {\n        nk_build(ctx);\n        ctx->build = nk_true;\n    }\n    iter = ctx->begin;\n    while (iter && ((iter->buffer.begin == iter->buffer.end) ||\n        (iter->flags & NK_WINDOW_HIDDEN) || iter->seq != ctx->seq))\n        iter = iter->next;\n    if (!iter) return 0;\n    return nk_ptr_add_const(struct nk_command, buffer, iter->buffer.begin);\n}\n\nNK_API const struct nk_command*\nnk__next(struct nk_context *ctx, const struct nk_command *cmd)\n{\n    nk_byte *buffer;\n    const struct nk_command *next;\n    NK_ASSERT(ctx);\n    if (!ctx || !cmd || !ctx->count) return 0;\n    if (cmd->next >= ctx->memory.allocated) return 0;\n    buffer = (nk_byte*)ctx->memory.memory.ptr;\n    next = nk_ptr_add_const(struct nk_command, buffer, cmd->next);\n    return next;\n}\n\n\n"
  },
  {
    "path": "src/nuklear_contextual.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ==============================================================\n *\n *                          CONTEXTUAL\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_contextual_begin(struct nk_context *ctx, nk_flags flags, struct nk_vec2 size,\n    struct nk_rect trigger_bounds)\n{\n    struct nk_window *win;\n    struct nk_window *popup;\n    struct nk_rect body;\n    struct nk_input* in;\n\n    NK_STORAGE const struct nk_rect null_rect = {-1,-1,0,0};\n    int is_clicked = 0;\n    int is_open = 0;\n    int ret = 0;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    ++win->popup.con_count;\n    if (ctx->current != ctx->active)\n        return 0;\n\n    /* check if currently active contextual is active */\n    popup = win->popup.win;\n    is_open = (popup && win->popup.type == NK_PANEL_CONTEXTUAL);\n    in = win->widgets_disabled ? 0 : &ctx->input;\n    if (in) {\n        is_clicked = nk_input_mouse_clicked(in, NK_BUTTON_RIGHT, trigger_bounds);\n        if (win->popup.active_con && win->popup.con_count != win->popup.active_con)\n            return 0;\n        if (!is_open && win->popup.active_con)\n            win->popup.active_con = 0;\n        if ((!is_open && !is_clicked))\n            return 0;\n\n        /* calculate contextual position on click */\n        win->popup.active_con = win->popup.con_count;\n        if (is_clicked) {\n            body.x = in->mouse.pos.x;\n            body.y = in->mouse.pos.y;\n        } else {\n            body.x = popup->bounds.x;\n            body.y = popup->bounds.y;\n        }\n\n        body.w = size.x;\n        body.h = size.y;\n\n        /* start nonblocking contextual popup */\n        ret = nk_nonblock_begin(ctx, flags | NK_WINDOW_NO_SCROLLBAR, body,\n            null_rect, NK_PANEL_CONTEXTUAL);\n        if (ret) win->popup.type = NK_PANEL_CONTEXTUAL;\n        else {\n            win->popup.active_con = 0;\n            win->popup.type = NK_PANEL_NONE;\n            if (win->popup.win)\n                win->popup.win->flags = 0;\n        }\n    }\n    return ret;\n}\nNK_API nk_bool\nnk_contextual_item_text(struct nk_context *ctx, const char *text, int len,\n    nk_flags alignment)\n{\n    struct nk_window *win;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);\n    if (!state) return nk_false;\n\n    in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,\n        text, len, alignment, NK_BUTTON_DEFAULT, &style->contextual_button, in, style->font)) {\n        nk_contextual_close(ctx);\n        return nk_true;\n    }\n    return nk_false;\n}\nNK_API nk_bool\nnk_contextual_item_label(struct nk_context *ctx, const char *label, nk_flags align)\n{\n    return nk_contextual_item_text(ctx, label, nk_strlen(label), align);\n}\nNK_API nk_bool\nnk_contextual_item_image_text(struct nk_context *ctx, struct nk_image img,\n    const char *text, int len, nk_flags align)\n{\n    struct nk_window *win;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);\n    if (!state) return nk_false;\n\n    in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, bounds,\n        img, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)){\n        nk_contextual_close(ctx);\n        return nk_true;\n    }\n    return nk_false;\n}\nNK_API nk_bool\nnk_contextual_item_image_label(struct nk_context *ctx, struct nk_image img,\n    const char *label, nk_flags align)\n{\n    return nk_contextual_item_image_text(ctx, img, label, nk_strlen(label), align);\n}\nNK_API nk_bool\nnk_contextual_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,\n    const char *text, int len, nk_flags align)\n{\n    struct nk_window *win;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);\n    if (!state) return nk_false;\n\n    in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,\n        symbol, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)) {\n        nk_contextual_close(ctx);\n        return nk_true;\n    }\n    return nk_false;\n}\nNK_API nk_bool\nnk_contextual_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,\n    const char *text, nk_flags align)\n{\n    return nk_contextual_item_symbol_text(ctx, symbol, text, nk_strlen(text), align);\n}\nNK_API void\nnk_contextual_close(struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) return;\n    nk_popup_close(ctx);\n}\nNK_API void\nnk_contextual_end(struct nk_context *ctx)\n{\n    struct nk_window *popup;\n    struct nk_panel *panel;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return;\n\n    popup = ctx->current;\n    panel = popup->layout;\n    NK_ASSERT(popup->parent);\n    NK_ASSERT((int)panel->type & (int)NK_PANEL_SET_POPUP);\n    if (panel->flags & NK_WINDOW_DYNAMIC) {\n        /* Close behavior\n        This is a bit of a hack solution since we do not know before we end our popup\n        how big it will be. We therefore do not directly know when a\n        click outside the non-blocking popup must close it at that direct frame.\n        Instead it will be closed in the next frame.*/\n        struct nk_rect body = {0,0,0,0};\n        if (panel->at_y < (panel->bounds.y + panel->bounds.h)) {\n            struct nk_vec2 padding = nk_panel_get_padding(&ctx->style, panel->type);\n            body = panel->bounds;\n            body.y = (panel->at_y + panel->footer_height + panel->border + padding.y + panel->row.height);\n            body.h = (panel->bounds.y + panel->bounds.h) - body.y;\n        }\n        {int pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);\n        int in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);\n        if (pressed && in_body)\n            popup->flags |= NK_WINDOW_HIDDEN;\n        }\n    }\n    if (popup->flags & NK_WINDOW_HIDDEN)\n        popup->seq = 0;\n    nk_popup_end(ctx);\n    return;\n}\n\n"
  },
  {
    "path": "src/nuklear_draw.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ==============================================================\n *\n *                          DRAW\n *\n * ===============================================================*/\nNK_LIB void\nnk_command_buffer_init(struct nk_command_buffer *cb,\n    struct nk_buffer *b, enum nk_command_clipping clip)\n{\n    NK_ASSERT(cb);\n    NK_ASSERT(b);\n    if (!cb || !b) return;\n    cb->base = b;\n    cb->use_clipping = (int)clip;\n    cb->begin = b->allocated;\n    cb->end = b->allocated;\n    cb->last = b->allocated;\n}\nNK_LIB void\nnk_command_buffer_reset(struct nk_command_buffer *b)\n{\n    NK_ASSERT(b);\n    if (!b) return;\n    b->begin = 0;\n    b->end = 0;\n    b->last = 0;\n    b->clip = nk_null_rect;\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    b->userdata.ptr = 0;\n#endif\n}\nNK_LIB void*\nnk_command_buffer_push(struct nk_command_buffer* b,\n    enum nk_command_type t, nk_size size)\n{\n    NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_command);\n    struct nk_command *cmd;\n    nk_size alignment;\n    void *unaligned;\n    void *memory;\n\n    NK_ASSERT(b);\n    NK_ASSERT(b->base);\n    if (!b) return 0;\n    cmd = (struct nk_command*)nk_buffer_alloc(b->base,NK_BUFFER_FRONT,size,align);\n    if (!cmd) return 0;\n\n    /* make sure the offset to the next command is aligned */\n    b->last = (nk_size)((nk_byte*)cmd - (nk_byte*)b->base->memory.ptr);\n    unaligned = (nk_byte*)cmd + size;\n    memory = NK_ALIGN_PTR(unaligned, align);\n    alignment = (nk_size)((nk_byte*)memory - (nk_byte*)unaligned);\n#ifdef NK_ZERO_COMMAND_MEMORY\n    NK_MEMSET(cmd, 0, size + alignment);\n#endif\n\n    cmd->type = t;\n    cmd->next = b->base->allocated + alignment;\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    cmd->userdata = b->userdata;\n#endif\n    b->end = cmd->next;\n    return cmd;\n}\nNK_API void\nnk_push_scissor(struct nk_command_buffer *b, struct nk_rect r)\n{\n    struct nk_command_scissor *cmd;\n    NK_ASSERT(b);\n    if (!b) return;\n\n    b->clip.x = r.x;\n    b->clip.y = r.y;\n    b->clip.w = r.w;\n    b->clip.h = r.h;\n    cmd = (struct nk_command_scissor*)\n        nk_command_buffer_push(b, NK_COMMAND_SCISSOR, sizeof(*cmd));\n\n    if (!cmd) return;\n    cmd->x = (short)r.x;\n    cmd->y = (short)r.y;\n    cmd->w = (unsigned short)NK_MAX(0, r.w);\n    cmd->h = (unsigned short)NK_MAX(0, r.h);\n}\nNK_API void\nnk_stroke_line(struct nk_command_buffer *b, float x0, float y0,\n    float x1, float y1, float line_thickness, struct nk_color c)\n{\n    struct nk_command_line *cmd;\n    NK_ASSERT(b);\n    if (!b || line_thickness <= 0) return;\n    cmd = (struct nk_command_line*)\n        nk_command_buffer_push(b, NK_COMMAND_LINE, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->begin.x = (short)x0;\n    cmd->begin.y = (short)y0;\n    cmd->end.x = (short)x1;\n    cmd->end.y = (short)y1;\n    cmd->color = c;\n}\nNK_API void\nnk_stroke_curve(struct nk_command_buffer *b, float ax, float ay,\n    float ctrl0x, float ctrl0y, float ctrl1x, float ctrl1y,\n    float bx, float by, float line_thickness, struct nk_color col)\n{\n    struct nk_command_curve *cmd;\n    NK_ASSERT(b);\n    if (!b || col.a == 0 || line_thickness <= 0) return;\n\n    cmd = (struct nk_command_curve*)\n        nk_command_buffer_push(b, NK_COMMAND_CURVE, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->begin.x = (short)ax;\n    cmd->begin.y = (short)ay;\n    cmd->ctrl[0].x = (short)ctrl0x;\n    cmd->ctrl[0].y = (short)ctrl0y;\n    cmd->ctrl[1].x = (short)ctrl1x;\n    cmd->ctrl[1].y = (short)ctrl1y;\n    cmd->end.x = (short)bx;\n    cmd->end.y = (short)by;\n    cmd->color = col;\n}\nNK_API void\nnk_stroke_rect(struct nk_command_buffer *b, struct nk_rect rect,\n    float rounding, float line_thickness, struct nk_color c)\n{\n    struct nk_command_rect *cmd;\n    NK_ASSERT(b);\n    if (!b || c.a == 0 || rect.w == 0 || rect.h == 0 || line_thickness <= 0) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,\n            clip->x, clip->y, clip->w, clip->h)) return;\n    }\n    cmd = (struct nk_command_rect*)\n        nk_command_buffer_push(b, NK_COMMAND_RECT, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->rounding = (unsigned short)rounding;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->x = (short)rect.x;\n    cmd->y = (short)rect.y;\n    cmd->w = (unsigned short)NK_MAX(0, rect.w);\n    cmd->h = (unsigned short)NK_MAX(0, rect.h);\n    cmd->color = c;\n}\nNK_API void\nnk_fill_rect(struct nk_command_buffer *b, struct nk_rect rect,\n    float rounding, struct nk_color c)\n{\n    struct nk_command_rect_filled *cmd;\n    NK_ASSERT(b);\n    if (!b || c.a == 0 || rect.w == 0 || rect.h == 0) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,\n            clip->x, clip->y, clip->w, clip->h)) return;\n    }\n\n    cmd = (struct nk_command_rect_filled*)\n        nk_command_buffer_push(b, NK_COMMAND_RECT_FILLED, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->rounding = (unsigned short)rounding;\n    cmd->x = (short)rect.x;\n    cmd->y = (short)rect.y;\n    cmd->w = (unsigned short)NK_MAX(0, rect.w);\n    cmd->h = (unsigned short)NK_MAX(0, rect.h);\n    cmd->color = c;\n}\nNK_API void\nnk_fill_rect_multi_color(struct nk_command_buffer *b, struct nk_rect rect,\n    struct nk_color left, struct nk_color top, struct nk_color right,\n    struct nk_color bottom)\n{\n    struct nk_command_rect_multi_color *cmd;\n    NK_ASSERT(b);\n    if (!b || rect.w == 0 || rect.h == 0) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,\n            clip->x, clip->y, clip->w, clip->h)) return;\n    }\n\n    cmd = (struct nk_command_rect_multi_color*)\n        nk_command_buffer_push(b, NK_COMMAND_RECT_MULTI_COLOR, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->x = (short)rect.x;\n    cmd->y = (short)rect.y;\n    cmd->w = (unsigned short)NK_MAX(0, rect.w);\n    cmd->h = (unsigned short)NK_MAX(0, rect.h);\n    cmd->left = left;\n    cmd->top = top;\n    cmd->right = right;\n    cmd->bottom = bottom;\n}\nNK_API void\nnk_stroke_circle(struct nk_command_buffer *b, struct nk_rect r,\n    float line_thickness, struct nk_color c)\n{\n    struct nk_command_circle *cmd;\n    if (!b || r.w == 0 || r.h == 0 || line_thickness <= 0) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))\n            return;\n    }\n\n    cmd = (struct nk_command_circle*)\n        nk_command_buffer_push(b, NK_COMMAND_CIRCLE, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->x = (short)r.x;\n    cmd->y = (short)r.y;\n    cmd->w = (unsigned short)NK_MAX(r.w, 0);\n    cmd->h = (unsigned short)NK_MAX(r.h, 0);\n    cmd->color = c;\n}\nNK_API void\nnk_fill_circle(struct nk_command_buffer *b, struct nk_rect r, struct nk_color c)\n{\n    struct nk_command_circle_filled *cmd;\n    NK_ASSERT(b);\n    if (!b || c.a == 0 || r.w == 0 || r.h == 0) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INTERSECT(r.x, r.y, r.w, r.h, clip->x, clip->y, clip->w, clip->h))\n            return;\n    }\n\n    cmd = (struct nk_command_circle_filled*)\n        nk_command_buffer_push(b, NK_COMMAND_CIRCLE_FILLED, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->x = (short)r.x;\n    cmd->y = (short)r.y;\n    cmd->w = (unsigned short)NK_MAX(r.w, 0);\n    cmd->h = (unsigned short)NK_MAX(r.h, 0);\n    cmd->color = c;\n}\nNK_API void\nnk_stroke_arc(struct nk_command_buffer *b, float cx, float cy, float radius,\n    float a_min, float a_max, float line_thickness, struct nk_color c)\n{\n    struct nk_command_arc *cmd;\n    if (!b || c.a == 0 || line_thickness <= 0) return;\n    cmd = (struct nk_command_arc*)\n        nk_command_buffer_push(b, NK_COMMAND_ARC, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->cx = (short)cx;\n    cmd->cy = (short)cy;\n    cmd->r = (unsigned short)radius;\n    cmd->a[0] = a_min;\n    cmd->a[1] = a_max;\n    cmd->color = c;\n}\nNK_API void\nnk_fill_arc(struct nk_command_buffer *b, float cx, float cy, float radius,\n    float a_min, float a_max, struct nk_color c)\n{\n    struct nk_command_arc_filled *cmd;\n    NK_ASSERT(b);\n    if (!b || c.a == 0) return;\n    cmd = (struct nk_command_arc_filled*)\n        nk_command_buffer_push(b, NK_COMMAND_ARC_FILLED, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->cx = (short)cx;\n    cmd->cy = (short)cy;\n    cmd->r = (unsigned short)radius;\n    cmd->a[0] = a_min;\n    cmd->a[1] = a_max;\n    cmd->color = c;\n}\nNK_API void\nnk_stroke_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,\n    float y1, float x2, float y2, float line_thickness, struct nk_color c)\n{\n    struct nk_command_triangle *cmd;\n    NK_ASSERT(b);\n    if (!b || c.a == 0 || line_thickness <= 0) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&\n            !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&\n            !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))\n            return;\n    }\n\n    cmd = (struct nk_command_triangle*)\n        nk_command_buffer_push(b, NK_COMMAND_TRIANGLE, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->a.x = (short)x0;\n    cmd->a.y = (short)y0;\n    cmd->b.x = (short)x1;\n    cmd->b.y = (short)y1;\n    cmd->c.x = (short)x2;\n    cmd->c.y = (short)y2;\n    cmd->color = c;\n}\nNK_API void\nnk_fill_triangle(struct nk_command_buffer *b, float x0, float y0, float x1,\n    float y1, float x2, float y2, struct nk_color c)\n{\n    struct nk_command_triangle_filled *cmd;\n    NK_ASSERT(b);\n    if (!b || c.a == 0) return;\n    if (!b) return;\n    if (b->use_clipping) {\n        const struct nk_rect *clip = &b->clip;\n        if (!NK_INBOX(x0, y0, clip->x, clip->y, clip->w, clip->h) &&\n            !NK_INBOX(x1, y1, clip->x, clip->y, clip->w, clip->h) &&\n            !NK_INBOX(x2, y2, clip->x, clip->y, clip->w, clip->h))\n            return;\n    }\n\n    cmd = (struct nk_command_triangle_filled*)\n        nk_command_buffer_push(b, NK_COMMAND_TRIANGLE_FILLED, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->a.x = (short)x0;\n    cmd->a.y = (short)y0;\n    cmd->b.x = (short)x1;\n    cmd->b.y = (short)y1;\n    cmd->c.x = (short)x2;\n    cmd->c.y = (short)y2;\n    cmd->color = c;\n}\nNK_API void\nnk_stroke_polygon(struct nk_command_buffer *b, const float *points, int point_count,\n    float line_thickness, struct nk_color col)\n{\n    int i;\n    nk_size size = 0;\n    struct nk_command_polygon *cmd;\n\n    NK_ASSERT(b);\n    if (!b || col.a == 0 || line_thickness <= 0) return;\n    size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;\n    cmd = (struct nk_command_polygon*) nk_command_buffer_push(b, NK_COMMAND_POLYGON, size);\n    if (!cmd) return;\n    cmd->color = col;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    cmd->point_count = (unsigned short)point_count;\n    for (i = 0; i < point_count; ++i) {\n        cmd->points[i].x = (short)points[i*2];\n        cmd->points[i].y = (short)points[i*2+1];\n    }\n}\nNK_API void\nnk_fill_polygon(struct nk_command_buffer *b, const float *points, int point_count,\n    struct nk_color col)\n{\n    int i;\n    nk_size size = 0;\n    struct nk_command_polygon_filled *cmd;\n\n    NK_ASSERT(b);\n    if (!b || col.a == 0) return;\n    size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;\n    cmd = (struct nk_command_polygon_filled*)\n        nk_command_buffer_push(b, NK_COMMAND_POLYGON_FILLED, size);\n    if (!cmd) return;\n    cmd->color = col;\n    cmd->point_count = (unsigned short)point_count;\n    for (i = 0; i < point_count; ++i) {\n        cmd->points[i].x = (short)points[i*2+0];\n        cmd->points[i].y = (short)points[i*2+1];\n    }\n}\nNK_API void\nnk_stroke_polyline(struct nk_command_buffer *b, const float *points, int point_count,\n    float line_thickness, struct nk_color col)\n{\n    int i;\n    nk_size size = 0;\n    struct nk_command_polyline *cmd;\n\n    NK_ASSERT(b);\n    if (!b || col.a == 0 || line_thickness <= 0) return;\n    size = sizeof(*cmd) + sizeof(short) * 2 * (nk_size)point_count;\n    cmd = (struct nk_command_polyline*) nk_command_buffer_push(b, NK_COMMAND_POLYLINE, size);\n    if (!cmd) return;\n    cmd->color = col;\n    cmd->point_count = (unsigned short)point_count;\n    cmd->line_thickness = (unsigned short)line_thickness;\n    for (i = 0; i < point_count; ++i) {\n        cmd->points[i].x = (short)points[i*2];\n        cmd->points[i].y = (short)points[i*2+1];\n    }\n}\nNK_API void\nnk_draw_image(struct nk_command_buffer *b, struct nk_rect r,\n    const struct nk_image *img, struct nk_color col)\n{\n    struct nk_command_image *cmd;\n    NK_ASSERT(b);\n    if (!b) return;\n    if (b->use_clipping) {\n        const struct nk_rect *c = &b->clip;\n        if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))\n            return;\n    }\n\n    cmd = (struct nk_command_image*)\n        nk_command_buffer_push(b, NK_COMMAND_IMAGE, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->x = (short)r.x;\n    cmd->y = (short)r.y;\n    cmd->w = (unsigned short)NK_MAX(0, r.w);\n    cmd->h = (unsigned short)NK_MAX(0, r.h);\n    cmd->img = *img;\n    cmd->col = col;\n}\nNK_API void\nnk_draw_nine_slice(struct nk_command_buffer *b, struct nk_rect r,\n    const struct nk_nine_slice *slc, struct nk_color col)\n{\n    struct nk_image img;\n    const struct nk_image *slcimg = (const struct nk_image*)slc;\n    nk_ushort rgnX, rgnY, rgnW, rgnH;\n    rgnX = slcimg->region[0];\n    rgnY = slcimg->region[1];\n    rgnW = slcimg->region[2];\n    rgnH = slcimg->region[3];\n\n    /* top-left */\n    img.handle = slcimg->handle;\n    img.w = slcimg->w;\n    img.h = slcimg->h;\n    img.region[0] = rgnX;\n    img.region[1] = rgnY;\n    img.region[2] = slc->l;\n    img.region[3] = slc->t;\n\n    nk_draw_image(b,\n        nk_rect(r.x, r.y, (float)slc->l, (float)slc->t),\n        &img, col);\n\n#define IMG_RGN(x, y, w, h) img.region[0] = (nk_ushort)(x); img.region[1] = (nk_ushort)(y); img.region[2] = (nk_ushort)(w); img.region[3] = (nk_ushort)(h);\n\n    /* top-center */\n    IMG_RGN(rgnX + slc->l, rgnY, rgnW - slc->l - slc->r, slc->t);\n    nk_draw_image(b,\n        nk_rect(r.x + (float)slc->l, r.y, (float)(r.w - slc->l - slc->r), (float)slc->t),\n        &img, col);\n\n    /* top-right */\n    IMG_RGN(rgnX + rgnW - slc->r, rgnY, slc->r, slc->t);\n    nk_draw_image(b,\n        nk_rect(r.x + r.w - (float)slc->r, r.y, (float)slc->r, (float)slc->t),\n        &img, col);\n\n    /* center-left */\n    IMG_RGN(rgnX, rgnY + slc->t, slc->l, rgnH - slc->t - slc->b);\n    nk_draw_image(b,\n        nk_rect(r.x, r.y + (float)slc->t, (float)slc->l, (float)(r.h - slc->t - slc->b)),\n        &img, col);\n\n    /* center */\n    IMG_RGN(rgnX + slc->l, rgnY + slc->t, rgnW - slc->l - slc->r, rgnH - slc->t - slc->b);\n    nk_draw_image(b,\n        nk_rect(r.x + (float)slc->l, r.y + (float)slc->t, (float)(r.w - slc->l - slc->r), (float)(r.h - slc->t - slc->b)),\n        &img, col);\n\n    /* center-right */\n    IMG_RGN(rgnX + rgnW - slc->r, rgnY + slc->t, slc->r, rgnH - slc->t - slc->b);\n    nk_draw_image(b,\n        nk_rect(r.x + r.w - (float)slc->r, r.y + (float)slc->t, (float)slc->r, (float)(r.h - slc->t - slc->b)),\n        &img, col);\n\n    /* bottom-left */\n    IMG_RGN(rgnX, rgnY + rgnH - slc->b, slc->l, slc->b);\n    nk_draw_image(b,\n        nk_rect(r.x, r.y + r.h - (float)slc->b, (float)slc->l, (float)slc->b),\n        &img, col);\n\n    /* bottom-center */\n    IMG_RGN(rgnX + slc->l, rgnY + rgnH - slc->b, rgnW - slc->l - slc->r, slc->b);\n    nk_draw_image(b,\n        nk_rect(r.x + (float)slc->l, r.y + r.h - (float)slc->b, (float)(r.w - slc->l - slc->r), (float)slc->b),\n        &img, col);\n\n    /* bottom-right */\n    IMG_RGN(rgnX + rgnW - slc->r, rgnY + rgnH - slc->b, slc->r, slc->b);\n    nk_draw_image(b,\n        nk_rect(r.x + r.w - (float)slc->r, r.y + r.h - (float)slc->b, (float)slc->r, (float)slc->b),\n        &img, col);\n\n#undef IMG_RGN\n}\nNK_API void\nnk_push_custom(struct nk_command_buffer *b, struct nk_rect r,\n    nk_command_custom_callback cb, nk_handle usr)\n{\n    struct nk_command_custom *cmd;\n    NK_ASSERT(b);\n    if (!b) return;\n    if (b->use_clipping) {\n        const struct nk_rect *c = &b->clip;\n        if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))\n            return;\n    }\n\n    cmd = (struct nk_command_custom*)\n        nk_command_buffer_push(b, NK_COMMAND_CUSTOM, sizeof(*cmd));\n    if (!cmd) return;\n    cmd->x = (short)r.x;\n    cmd->y = (short)r.y;\n    cmd->w = (unsigned short)NK_MAX(0, r.w);\n    cmd->h = (unsigned short)NK_MAX(0, r.h);\n    cmd->callback_data = usr;\n    cmd->callback = cb;\n}\nNK_API void\nnk_draw_text(struct nk_command_buffer *b, struct nk_rect r,\n    const char *string, int length, const struct nk_user_font *font,\n    struct nk_color bg, struct nk_color fg)\n{\n    float text_width = 0;\n    struct nk_command_text *cmd;\n\n    NK_ASSERT(b);\n    NK_ASSERT(font);\n    if (!b || !string || !length || (bg.a == 0 && fg.a == 0)) return;\n    if (b->use_clipping) {\n        const struct nk_rect *c = &b->clip;\n        if (c->w == 0 || c->h == 0 || !NK_INTERSECT(r.x, r.y, r.w, r.h, c->x, c->y, c->w, c->h))\n            return;\n    }\n\n    /* make sure text fits inside bounds */\n    text_width = font->width(font->userdata, font->height, string, length);\n    if (text_width > r.w){\n        int glyphs = 0;\n        float txt_width = (float)text_width;\n        length = nk_text_clamp(font, string, length, r.w, &glyphs, &txt_width, 0,0);\n    }\n\n    if (!length) return;\n    cmd = (struct nk_command_text*)\n        nk_command_buffer_push(b, NK_COMMAND_TEXT, sizeof(*cmd) + (nk_size)(length + 1));\n    if (!cmd) return;\n    cmd->x = (short)r.x;\n    cmd->y = (short)r.y;\n    cmd->w = (unsigned short)r.w;\n    cmd->h = (unsigned short)r.h;\n    cmd->background = bg;\n    cmd->foreground = fg;\n    cmd->font = font;\n    cmd->length = length;\n    cmd->height = font->height;\n    NK_MEMCPY(cmd->string, string, (nk_size)length);\n    cmd->string[length] = '\\0';\n}\n"
  },
  {
    "path": "src/nuklear_edit.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                          FILTER\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_filter_default(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(unicode);\n    NK_UNUSED(box);\n    return nk_true;\n}\nNK_API nk_bool\nnk_filter_ascii(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(box);\n    if (unicode > 128) return nk_false;\n    else return nk_true;\n}\nNK_API nk_bool\nnk_filter_float(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(box);\n    if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-')\n        return nk_false;\n    else return nk_true;\n}\nNK_API nk_bool\nnk_filter_decimal(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(box);\n    if ((unicode < '0' || unicode > '9') && unicode != '-')\n        return nk_false;\n    else return nk_true;\n}\nNK_API nk_bool\nnk_filter_hex(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(box);\n    if ((unicode < '0' || unicode > '9') &&\n        (unicode < 'a' || unicode > 'f') &&\n        (unicode < 'A' || unicode > 'F'))\n        return nk_false;\n    else return nk_true;\n}\nNK_API nk_bool\nnk_filter_oct(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(box);\n    if (unicode < '0' || unicode > '7')\n        return nk_false;\n    else return nk_true;\n}\nNK_API nk_bool\nnk_filter_binary(const struct nk_text_edit *box, nk_rune unicode)\n{\n    NK_UNUSED(box);\n    if (unicode != '0' && unicode != '1')\n        return nk_false;\n    else return nk_true;\n}\n\n/* ===============================================================\n *\n *                          EDIT\n *\n * ===============================================================*/\nNK_LIB void\nnk_edit_draw_text(struct nk_command_buffer *out,\n    const struct nk_style_edit *style, float pos_x, float pos_y,\n    float x_offset, const char *text, int byte_len, float row_height,\n    const struct nk_user_font *font, struct nk_color background,\n    struct nk_color foreground, nk_bool is_selected)\n{\n    NK_ASSERT(out);\n    NK_ASSERT(font);\n    NK_ASSERT(style);\n    if (!text || !byte_len || !out || !style) return;\n\n    {int glyph_len = 0;\n    nk_rune unicode = 0;\n    int text_len = 0;\n    float line_width = 0;\n    float glyph_width;\n    const char *line = text;\n    float line_offset = 0;\n    int line_count = 0;\n\n    struct nk_text txt;\n    txt.padding = nk_vec2(0,0);\n    txt.background = background;\n    txt.text = foreground;\n\n    foreground = nk_rgb_factor(foreground, style->color_factor);\n    background = nk_rgb_factor(background, style->color_factor);\n\n    glyph_len = nk_utf_decode(text+text_len, &unicode, byte_len-text_len);\n    if (!glyph_len) return;\n    while ((text_len < byte_len) && glyph_len)\n    {\n        if (unicode == '\\n') {\n            /* new line separator so draw previous line */\n            struct nk_rect label;\n            label.y = pos_y + line_offset;\n            label.h = row_height;\n            label.w = line_width;\n            label.x = pos_x;\n            if (!line_count)\n                label.x += x_offset;\n\n            if (is_selected) /* selection needs to draw different background color */\n                nk_fill_rect(out, label, 0, background);\n            nk_widget_text(out, label, line, (int)((text + text_len) - line),\n                &txt, NK_TEXT_CENTERED, font);\n\n            text_len++;\n            line_count++;\n            line_width = 0;\n            line = text + text_len;\n            line_offset += row_height;\n            glyph_len = nk_utf_decode(text + text_len, &unicode, (int)(byte_len-text_len));\n            continue;\n        }\n        if (unicode == '\\r') {\n            text_len++;\n            glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);\n            continue;\n        }\n        glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);\n        line_width += (float)glyph_width;\n        text_len += glyph_len;\n        glyph_len = nk_utf_decode(text + text_len, &unicode, byte_len-text_len);\n        continue;\n    }\n    if (line_width > 0) {\n        /* draw last line */\n        struct nk_rect label;\n        label.y = pos_y + line_offset;\n        label.h = row_height;\n        label.w = line_width;\n        label.x = pos_x;\n        if (!line_count)\n            label.x += x_offset;\n\n        if (is_selected)\n            nk_fill_rect(out, label, 0, background);\n        nk_widget_text(out, label, line, (int)((text + text_len) - line),\n            &txt, NK_TEXT_LEFT, font);\n    }}\n}\nNK_LIB nk_flags\nnk_do_edit(nk_flags *state, struct nk_command_buffer *out,\n    struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter,\n    struct nk_text_edit *edit, const struct nk_style_edit *style,\n    struct nk_input *in, const struct nk_user_font *font)\n{\n    struct nk_rect area;\n    nk_flags ret = 0;\n    float row_height;\n    char prev_state = 0;\n    char is_hovered = 0;\n    char select_all = 0;\n    char cursor_follow = 0;\n    struct nk_rect old_clip;\n    struct nk_rect clip;\n\n    NK_ASSERT(state);\n    NK_ASSERT(out);\n    NK_ASSERT(style);\n    if (!state || !out || !style)\n        return ret;\n\n    /* visible text area calculation */\n    area.x = bounds.x + style->padding.x + style->border;\n    area.y = bounds.y + style->padding.y + style->border;\n    area.w = bounds.w - (2.0f * style->padding.x + 2 * style->border);\n    area.h = bounds.h - (2.0f * style->padding.y + 2 * style->border);\n    if (flags & NK_EDIT_MULTILINE)\n        area.w = NK_MAX(0, area.w - style->scrollbar_size.x);\n    row_height = (flags & NK_EDIT_MULTILINE)? font->height + style->row_padding: area.h;\n\n    /* calculate clipping rectangle */\n    old_clip = out->clip;\n    nk_unify(&clip, &old_clip, area.x, area.y, area.x + area.w, area.y + area.h);\n\n    /* update edit state */\n    prev_state = (char)edit->active;\n    if (in && in->mouse.buttons[NK_BUTTON_LEFT].clicked && in->mouse.buttons[NK_BUTTON_LEFT].down) {\n        edit->active = NK_INBOX(in->mouse.pos.x, in->mouse.pos.y,\n                                bounds.x, bounds.y, bounds.w, bounds.h);\n    }\n\n    /* (de)activate text editor */\n    if (!prev_state && edit->active) {\n        const enum nk_text_edit_type type = (flags & NK_EDIT_MULTILINE) ?\n            NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE;\n        /* keep scroll position when re-activating edit widget */\n        struct nk_vec2 oldscrollbar = edit->scrollbar;\n        nk_textedit_clear_state(edit, type, filter);\n        edit->scrollbar = oldscrollbar;\n        if (flags & NK_EDIT_AUTO_SELECT)\n            select_all = nk_true;\n        if (flags & NK_EDIT_GOTO_END_ON_ACTIVATE) {\n            edit->cursor = edit->string.len;\n            in = 0;\n        }\n    } else if (!edit->active) edit->mode = NK_TEXT_EDIT_MODE_VIEW;\n    if (flags & NK_EDIT_READ_ONLY)\n        edit->mode = NK_TEXT_EDIT_MODE_VIEW;\n    else if (flags & NK_EDIT_ALWAYS_INSERT_MODE)\n        edit->mode = NK_TEXT_EDIT_MODE_INSERT;\n\n    ret = (edit->active) ? NK_EDIT_ACTIVE: NK_EDIT_INACTIVE;\n    if (prev_state != edit->active)\n        ret |= (edit->active) ? NK_EDIT_ACTIVATED: NK_EDIT_DEACTIVATED;\n\n    /* handle user input */\n    if (edit->active && in)\n    {\n        int shift_mod = in->keyboard.keys[NK_KEY_SHIFT].down;\n        const float mouse_x = (in->mouse.pos.x - area.x) + edit->scrollbar.x;\n        const float mouse_y = (in->mouse.pos.y - area.y) + edit->scrollbar.y;\n\n        /* mouse click handler */\n        is_hovered = (char)nk_input_is_mouse_hovering_rect(in, area);\n        if (select_all) {\n            nk_textedit_select_all(edit);\n        } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked) {\n            nk_textedit_click(edit, mouse_x, mouse_y, font, row_height);\n        } else if (is_hovered && in->mouse.buttons[NK_BUTTON_LEFT].down &&\n            nk_input_is_mouse_moved(in)) {\n            nk_textedit_drag(edit, mouse_x, mouse_y, font, row_height);\n            cursor_follow = nk_true;\n        } else if (is_hovered && in->mouse.buttons[NK_BUTTON_RIGHT].clicked &&\n            in->mouse.buttons[NK_BUTTON_RIGHT].down) {\n            nk_textedit_key(edit, NK_KEY_TEXT_WORD_LEFT, nk_false, font, row_height);\n            nk_textedit_key(edit, NK_KEY_TEXT_WORD_RIGHT, nk_true, font, row_height);\n            cursor_follow = nk_true;\n        }\n\n        {int i; /* keyboard input */\n        int old_mode = edit->mode;\n        for (i = 0; i < NK_KEY_MAX; ++i) {\n            if (i == NK_KEY_ENTER || i == NK_KEY_TAB) continue; /* special case */\n            if (nk_input_is_key_pressed(in, (enum nk_keys)i)) {\n                nk_textedit_key(edit, (enum nk_keys)i, shift_mod, font, row_height);\n                cursor_follow = nk_true;\n            }\n        }\n        if (old_mode != edit->mode) {\n            in->keyboard.text_len = 0;\n        }}\n\n        /* text input */\n        edit->filter = filter;\n        if (in->keyboard.text_len) {\n            nk_textedit_text(edit, in->keyboard.text, in->keyboard.text_len);\n            cursor_follow = nk_true;\n            in->keyboard.text_len = 0;\n        }\n\n        /* enter key handler */\n        if (nk_input_is_key_pressed(in, NK_KEY_ENTER)) {\n            cursor_follow = nk_true;\n            if (flags & NK_EDIT_CTRL_ENTER_NEWLINE && shift_mod)\n                nk_textedit_text(edit, \"\\n\", 1);\n            else if (flags & NK_EDIT_SIG_ENTER)\n                ret |= NK_EDIT_COMMITED;\n            else nk_textedit_text(edit, \"\\n\", 1);\n        }\n\n        /* cut & copy handler */\n        {int copy= nk_input_is_key_pressed(in, NK_KEY_COPY);\n        int cut = nk_input_is_key_pressed(in, NK_KEY_CUT);\n        if ((copy || cut) && (flags & NK_EDIT_CLIPBOARD))\n        {\n            int glyph_len;\n            nk_rune unicode;\n            const char *text;\n            int b = edit->select_start;\n            int e = edit->select_end;\n\n            int begin = NK_MIN(b, e);\n            int end = NK_MAX(b, e);\n            text = nk_str_at_const(&edit->string, begin, &unicode, &glyph_len);\n            if (edit->clip.copy)\n                edit->clip.copy(edit->clip.userdata, text, end - begin);\n            if (cut && !(flags & NK_EDIT_READ_ONLY)){\n                nk_textedit_cut(edit);\n                cursor_follow = nk_true;\n            }\n        }}\n\n        /* paste handler */\n        {int paste = nk_input_is_key_pressed(in, NK_KEY_PASTE);\n        if (paste && (flags & NK_EDIT_CLIPBOARD) && edit->clip.paste) {\n            edit->clip.paste(edit->clip.userdata, edit);\n            cursor_follow = nk_true;\n        }}\n\n        /* tab handler */\n        {int tab = nk_input_is_key_pressed(in, NK_KEY_TAB);\n        if (tab && (flags & NK_EDIT_ALLOW_TAB)) {\n            nk_textedit_text(edit, \"    \", 4);\n            cursor_follow = nk_true;\n        }}\n    }\n\n    /* set widget state */\n    if (edit->active)\n        *state = NK_WIDGET_STATE_ACTIVE;\n    else nk_widget_state_reset(state);\n\n    if (is_hovered)\n        *state |= NK_WIDGET_STATE_HOVERED;\n\n    /* DRAW EDIT */\n    {const char *text = nk_str_get_const(&edit->string);\n    int len = nk_str_len_char(&edit->string);\n\n    {/* select background colors/images  */\n    const struct nk_style_item *background;\n    if (*state & NK_WIDGET_STATE_ACTIVED)\n        background = &style->active;\n    else if (*state & NK_WIDGET_STATE_HOVER)\n        background = &style->hover;\n    else background = &style->normal;\n\n    /* draw background frame */\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));\n            nk_stroke_rect(out, bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));\n            break;\n    }}\n\n\n    area.w = NK_MAX(0, area.w - style->cursor_size);\n    if (edit->active)\n    {\n        int total_lines = 1;\n        struct nk_vec2 text_size = nk_vec2(0,0);\n\n        /* text pointer positions */\n        const char *cursor_ptr = 0;\n        const char *select_begin_ptr = 0;\n        const char *select_end_ptr = 0;\n\n        /* 2D pixel positions */\n        struct nk_vec2 cursor_pos = nk_vec2(0,0);\n        struct nk_vec2 selection_offset_start = nk_vec2(0,0);\n        struct nk_vec2 selection_offset_end = nk_vec2(0,0);\n\n        int selection_begin = NK_MIN(edit->select_start, edit->select_end);\n        int selection_end = NK_MAX(edit->select_start, edit->select_end);\n\n        /* calculate total line count + total space + cursor/selection position */\n        float line_width = 0.0f;\n        if (text && len)\n        {\n            /* utf8 encoding */\n            float glyph_width;\n            int glyph_len = 0;\n            nk_rune unicode = 0;\n            int text_len = 0;\n            int glyphs = 0;\n            int row_begin = 0;\n\n            glyph_len = nk_utf_decode(text, &unicode, len);\n            glyph_width = font->width(font->userdata, font->height, text, glyph_len);\n            line_width = 0;\n\n            /* iterate all lines */\n            while ((text_len < len) && glyph_len)\n            {\n                /* set cursor 2D position and line */\n                if (!cursor_ptr && glyphs == edit->cursor)\n                {\n                    int glyph_offset;\n                    struct nk_vec2 out_offset;\n                    struct nk_vec2 row_size;\n                    const char *remaining;\n\n                    /* calculate 2d position */\n                    cursor_pos.y = (float)(total_lines-1) * row_height;\n                    row_size = nk_text_calculate_text_bounds(font, text+row_begin,\n                                text_len-row_begin, row_height, &remaining,\n                                &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);\n                    cursor_pos.x = row_size.x;\n                    cursor_ptr = text + text_len;\n                }\n\n                /* set start selection 2D position and line */\n                if (!select_begin_ptr && edit->select_start != edit->select_end &&\n                    glyphs == selection_begin)\n                {\n                    int glyph_offset;\n                    struct nk_vec2 out_offset;\n                    struct nk_vec2 row_size;\n                    const char *remaining;\n\n                    /* calculate 2d position */\n                    selection_offset_start.y = (float)(NK_MAX(total_lines-1,0)) * row_height;\n                    row_size = nk_text_calculate_text_bounds(font, text+row_begin,\n                                text_len-row_begin, row_height, &remaining,\n                                &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);\n                    selection_offset_start.x = row_size.x;\n                    select_begin_ptr = text + text_len;\n                }\n\n                /* set end selection 2D position and line */\n                if (!select_end_ptr && edit->select_start != edit->select_end &&\n                    glyphs == selection_end)\n                {\n                    int glyph_offset;\n                    struct nk_vec2 out_offset;\n                    struct nk_vec2 row_size;\n                    const char *remaining;\n\n                    /* calculate 2d position */\n                    selection_offset_end.y = (float)(total_lines-1) * row_height;\n                    row_size = nk_text_calculate_text_bounds(font, text+row_begin,\n                                text_len-row_begin, row_height, &remaining,\n                                &out_offset, &glyph_offset, NK_STOP_ON_NEW_LINE);\n                    selection_offset_end.x = row_size.x;\n                    select_end_ptr = text + text_len;\n                }\n                if (unicode == '\\n') {\n                    text_size.x = NK_MAX(text_size.x, line_width);\n                    total_lines++;\n                    line_width = 0;\n                    text_len++;\n                    glyphs++;\n                    row_begin = text_len;\n                    glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);\n                    glyph_width = font->width(font->userdata, font->height, text+text_len, glyph_len);\n                    continue;\n                }\n\n                glyphs++;\n                text_len += glyph_len;\n                line_width += (float)glyph_width;\n\n                glyph_len = nk_utf_decode(text + text_len, &unicode, len-text_len);\n                glyph_width = font->width(font->userdata, font->height,\n                    text+text_len, glyph_len);\n                continue;\n            }\n            text_size.y = (float)total_lines * row_height;\n\n            /* handle case when cursor is at end of text buffer */\n            if (!cursor_ptr && edit->cursor == edit->string.len) {\n                cursor_pos.x = line_width;\n                cursor_pos.y = text_size.y - row_height;\n            }\n        }\n        {\n            /* scrollbar */\n            if (cursor_follow)\n            {\n                /* update scrollbar to follow cursor */\n                if (!(flags & NK_EDIT_NO_HORIZONTAL_SCROLL)) {\n                    /* horizontal scroll */\n                    const float scroll_increment = area.w * 0.25f;\n                    if (cursor_pos.x < edit->scrollbar.x)\n                        edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - scroll_increment);\n                    if (cursor_pos.x >= edit->scrollbar.x + area.w)\n                        edit->scrollbar.x = (float)(int)NK_MAX(0.0f, cursor_pos.x - area.w + scroll_increment);\n                } else edit->scrollbar.x = 0;\n\n                if (flags & NK_EDIT_MULTILINE) {\n                    /* vertical scroll: like horizontal, it only adjusts if the\n                     * cursor leaves the visible area, and then only just enough\n                     * to keep it visible */\n                    if (cursor_pos.y < edit->scrollbar.y)\n                        edit->scrollbar.y = NK_MAX(0.0f, cursor_pos.y);\n                    if (cursor_pos.y > edit->scrollbar.y + area.h - row_height)\n                        edit->scrollbar.y = edit->scrollbar.y + row_height;\n                } else edit->scrollbar.y = 0;\n            }\n\n            /* scrollbar widget */\n            if (flags & NK_EDIT_MULTILINE)\n            {\n                nk_flags ws;\n                struct nk_rect scroll;\n                float scroll_target;\n                float scroll_offset;\n                float scroll_step;\n                float scroll_inc;\n\n                scroll = area;\n                scroll.x = (bounds.x + bounds.w - style->border) - style->scrollbar_size.x;\n                scroll.w = style->scrollbar_size.x;\n\n                scroll_offset = edit->scrollbar.y;\n                scroll_step = scroll.h * 0.10f;\n                scroll_inc = scroll.h * 0.01f;\n                scroll_target = text_size.y;\n                edit->scrollbar.y = nk_do_scrollbarv(&ws, out, scroll, is_hovered,\n                        scroll_offset, scroll_target, scroll_step, scroll_inc,\n                        &style->scrollbar, in, font);\n                /* Eat mouse scroll if we're active */\n                if (is_hovered && in->mouse.scroll_delta.y) {\n                    in->mouse.scroll_delta.y = 0;\n                }\n            }\n        }\n\n        /* draw text */\n        {struct nk_color background_color;\n        struct nk_color text_color;\n        struct nk_color sel_background_color;\n        struct nk_color sel_text_color;\n        struct nk_color cursor_color;\n        struct nk_color cursor_text_color;\n        const struct nk_style_item *background;\n        nk_push_scissor(out, clip);\n\n        /* select correct colors to draw */\n        if (*state & NK_WIDGET_STATE_ACTIVED) {\n            background = &style->active;\n            text_color = style->text_active;\n            sel_text_color = style->selected_text_hover;\n            sel_background_color = style->selected_hover;\n            cursor_color = style->cursor_hover;\n            cursor_text_color = style->cursor_text_hover;\n        } else if (*state & NK_WIDGET_STATE_HOVER) {\n            background = &style->hover;\n            text_color = style->text_hover;\n            sel_text_color = style->selected_text_hover;\n            sel_background_color = style->selected_hover;\n            cursor_text_color = style->cursor_text_hover;\n            cursor_color = style->cursor_hover;\n        } else {\n            background = &style->normal;\n            text_color = style->text_normal;\n            sel_text_color = style->selected_text_normal;\n            sel_background_color = style->selected_normal;\n            cursor_color = style->cursor_normal;\n            cursor_text_color = style->cursor_text_normal;\n        }\n        if (background->type == NK_STYLE_ITEM_IMAGE)\n            background_color = nk_rgba(0,0,0,0);\n        else\n            background_color = background->data.color;\n\n        cursor_color = nk_rgb_factor(cursor_color, style->color_factor);\n        cursor_text_color = nk_rgb_factor(cursor_text_color, style->color_factor);\n\n        if (edit->select_start == edit->select_end) {\n            /* no selection so just draw the complete text */\n            const char *begin = nk_str_get_const(&edit->string);\n            int l = nk_str_len_char(&edit->string);\n            nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,\n                area.y - edit->scrollbar.y, 0, begin, l, row_height, font,\n                background_color, text_color, nk_false);\n        } else {\n            /* edit has selection so draw 1-3 text chunks */\n            if (edit->select_start != edit->select_end && selection_begin > 0){\n                /* draw unselected text before selection */\n                const char *begin = nk_str_get_const(&edit->string);\n                NK_ASSERT(select_begin_ptr);\n                nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,\n                    area.y - edit->scrollbar.y, 0, begin, (int)(select_begin_ptr - begin),\n                    row_height, font, background_color, text_color, nk_false);\n            }\n            if (edit->select_start != edit->select_end) {\n                /* draw selected text */\n                NK_ASSERT(select_begin_ptr);\n                if (!select_end_ptr) {\n                    const char *begin = nk_str_get_const(&edit->string);\n                    select_end_ptr = begin + nk_str_len_char(&edit->string);\n                }\n                nk_edit_draw_text(out, style,\n                    area.x - edit->scrollbar.x,\n                    area.y + selection_offset_start.y - edit->scrollbar.y,\n                    selection_offset_start.x,\n                    select_begin_ptr, (int)(select_end_ptr - select_begin_ptr),\n                    row_height, font, sel_background_color, sel_text_color, nk_true);\n            }\n            if ((edit->select_start != edit->select_end &&\n                selection_end < edit->string.len))\n            {\n                /* draw unselected text after selected text */\n                const char *begin = select_end_ptr;\n                const char *end = nk_str_get_const(&edit->string) +\n                                    nk_str_len_char(&edit->string);\n                NK_ASSERT(select_end_ptr);\n                nk_edit_draw_text(out, style,\n                    area.x - edit->scrollbar.x,\n                    area.y + selection_offset_end.y - edit->scrollbar.y,\n                    selection_offset_end.x,\n                    begin, (int)(end - begin), row_height, font,\n                    background_color, text_color, nk_true);\n            }\n        }\n\n        /* cursor */\n        if (edit->select_start == edit->select_end)\n        {\n            if (edit->cursor >= nk_str_len(&edit->string) ||\n                (cursor_ptr && *cursor_ptr == '\\n')) {\n                /* draw cursor at end of line */\n                struct nk_rect cursor;\n                cursor.w = style->cursor_size;\n                cursor.h = font->height;\n                cursor.x = area.x + cursor_pos.x - edit->scrollbar.x;\n                cursor.y = area.y + cursor_pos.y + row_height/2.0f - cursor.h/2.0f;\n                cursor.y -= edit->scrollbar.y;\n                nk_fill_rect(out, cursor, 0, cursor_color);\n            } else {\n                /* draw cursor inside text */\n                int glyph_len;\n                struct nk_rect label;\n                struct nk_text txt;\n\n                nk_rune unicode;\n                NK_ASSERT(cursor_ptr);\n                glyph_len = nk_utf_decode(cursor_ptr, &unicode, 4);\n\n                label.x = area.x + cursor_pos.x - edit->scrollbar.x;\n                label.y = area.y + cursor_pos.y - edit->scrollbar.y;\n                label.w = font->width(font->userdata, font->height, cursor_ptr, glyph_len);\n                label.h = row_height;\n\n                txt.padding = nk_vec2(0,0);\n                txt.background = cursor_color;;\n                txt.text = cursor_text_color;\n                nk_fill_rect(out, label, 0, cursor_color);\n                nk_widget_text(out, label, cursor_ptr, glyph_len, &txt, NK_TEXT_LEFT, font);\n            }\n        }}\n    } else {\n        /* not active so just draw text */\n        int l = nk_str_len_char(&edit->string);\n        const char *begin = nk_str_get_const(&edit->string);\n\n        const struct nk_style_item *background;\n        struct nk_color background_color;\n        struct nk_color text_color;\n        nk_push_scissor(out, clip);\n        if (*state & NK_WIDGET_STATE_ACTIVED) {\n            background = &style->active;\n            text_color = style->text_active;\n        } else if (*state & NK_WIDGET_STATE_HOVER) {\n            background = &style->hover;\n            text_color = style->text_hover;\n        } else {\n            background = &style->normal;\n            text_color = style->text_normal;\n        }\n        if (background->type == NK_STYLE_ITEM_IMAGE)\n            background_color = nk_rgba(0,0,0,0);\n        else\n            background_color = background->data.color;\n\n        background_color = nk_rgb_factor(background_color, style->color_factor);\n        text_color = nk_rgb_factor(text_color, style->color_factor);\n\n        nk_edit_draw_text(out, style, area.x - edit->scrollbar.x,\n            area.y - edit->scrollbar.y, 0, begin, l, row_height, font,\n            background_color, text_color, nk_false);\n    }\n    nk_push_scissor(out, old_clip);}\n    return ret;\n}\nNK_API void\nnk_edit_focus(struct nk_context *ctx, nk_flags flags)\n{\n    nk_hash hash;\n    struct nk_window *win;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return;\n\n    win = ctx->current;\n    hash = win->edit.seq;\n    win->edit.active = nk_true;\n    win->edit.name = hash;\n    if (flags & NK_EDIT_ALWAYS_INSERT_MODE)\n        win->edit.mode = NK_TEXT_EDIT_MODE_INSERT;\n}\nNK_API void\nnk_edit_unfocus(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return;\n\n    win = ctx->current;\n    win->edit.active = nk_false;\n    win->edit.name = 0;\n}\nNK_API nk_flags\nnk_edit_string(struct nk_context *ctx, nk_flags flags,\n    char *memory, int *len, int max, nk_plugin_filter filter)\n{\n    nk_hash hash;\n    nk_flags state;\n    struct nk_text_edit *edit;\n    struct nk_window *win;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(memory);\n    NK_ASSERT(len);\n    if (!ctx || !memory || !len)\n        return 0;\n\n    filter = (!filter) ? nk_filter_default: filter;\n    win = ctx->current;\n    hash = win->edit.seq;\n    edit = &ctx->text_edit;\n    nk_textedit_clear_state(&ctx->text_edit, (flags & NK_EDIT_MULTILINE)?\n        NK_TEXT_EDIT_MULTI_LINE: NK_TEXT_EDIT_SINGLE_LINE, filter);\n\n    if (win->edit.active && hash == win->edit.name) {\n        if (flags & NK_EDIT_NO_CURSOR)\n            edit->cursor = nk_utf_len(memory, *len);\n        else edit->cursor = win->edit.cursor;\n        if (!(flags & NK_EDIT_SELECTABLE)) {\n            edit->select_start = win->edit.cursor;\n            edit->select_end = win->edit.cursor;\n        } else {\n            edit->select_start = win->edit.sel_start;\n            edit->select_end = win->edit.sel_end;\n        }\n        edit->mode = win->edit.mode;\n        edit->scrollbar.x = (float)win->edit.scrollbar.x;\n        edit->scrollbar.y = (float)win->edit.scrollbar.y;\n        edit->active = nk_true;\n    } else edit->active = nk_false;\n\n    max = NK_MAX(1, max);\n    *len = NK_MIN(*len, max-1);\n    nk_str_init_fixed(&edit->string, memory, (nk_size)max);\n    edit->string.buffer.allocated = (nk_size)*len;\n    edit->string.len = nk_utf_len(memory, *len);\n    state = nk_edit_buffer(ctx, flags, edit, filter);\n    *len = (int)edit->string.buffer.allocated;\n\n    if (edit->active) {\n        win->edit.cursor = edit->cursor;\n        win->edit.sel_start = edit->select_start;\n        win->edit.sel_end = edit->select_end;\n        win->edit.mode = edit->mode;\n        win->edit.scrollbar.x = (nk_uint)edit->scrollbar.x;\n        win->edit.scrollbar.y = (nk_uint)edit->scrollbar.y;\n    } return state;\n}\nNK_API nk_flags\nnk_edit_buffer(struct nk_context *ctx, nk_flags flags,\n    struct nk_text_edit *edit, nk_plugin_filter filter)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    struct nk_input *in;\n\n    enum nk_widget_layout_states state;\n    struct nk_rect bounds;\n\n    nk_flags ret_flags = 0;\n    unsigned char prev_state;\n    nk_hash hash;\n\n    /* make sure correct values */\n    NK_ASSERT(ctx);\n    NK_ASSERT(edit);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    state = nk_widget(&bounds, ctx);\n    if (!state) return state;\n    else if (state == NK_WIDGET_DISABLED)\n        flags |= NK_EDIT_READ_ONLY;\n    in = (win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n\n    /* check if edit is currently hot item */\n    hash = win->edit.seq++;\n    if (win->edit.active && hash == win->edit.name) {\n        if (flags & NK_EDIT_NO_CURSOR)\n            edit->cursor = edit->string.len;\n        if (!(flags & NK_EDIT_SELECTABLE)) {\n            edit->select_start = edit->cursor;\n            edit->select_end = edit->cursor;\n        }\n        if (flags & NK_EDIT_CLIPBOARD)\n            edit->clip = ctx->clip;\n        edit->active = (unsigned char)win->edit.active;\n    } else edit->active = nk_false;\n    edit->mode = win->edit.mode;\n\n    filter = (!filter) ? nk_filter_default: filter;\n    prev_state = (unsigned char)edit->active;\n    in = (flags & NK_EDIT_READ_ONLY) ? 0: in;\n    ret_flags = nk_do_edit(&ctx->last_widget_state, &win->buffer, bounds, flags,\n                    filter, edit, &style->edit, in, style->font);\n\n    if (ctx->last_widget_state & NK_WIDGET_STATE_HOVER)\n        ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_TEXT];\n    if (edit->active && prev_state != edit->active) {\n        /* current edit is now hot */\n        win->edit.active = nk_true;\n        win->edit.name = hash;\n    } else if (prev_state && !edit->active) {\n        /* current edit is now cold */\n        win->edit.active = nk_false;\n    } return ret_flags;\n}\nNK_API nk_flags\nnk_edit_string_zero_terminated(struct nk_context *ctx, nk_flags flags,\n    char *buffer, int max, nk_plugin_filter filter)\n{\n    nk_flags result;\n    int len = nk_strlen(buffer);\n    result = nk_edit_string(ctx, flags, buffer, &len, max, filter);\n    buffer[NK_MIN(NK_MAX(max-1,0), len)] = '\\0';\n    return result;\n}\n\n"
  },
  {
    "path": "src/nuklear_font.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n#ifdef NK_INCLUDE_FONT_BAKING\n/* -------------------------------------------------------------\n *\n *                          RECT PACK\n *\n * --------------------------------------------------------------*/\n\n#include \"stb_rect_pack.h\"\n\n/*\n * ==============================================================\n *\n *                          TRUETYPE\n *\n * ===============================================================\n */\n#define STBTT_MAX_OVERSAMPLE   8\n#include \"stb_truetype.h\"\n\n/* -------------------------------------------------------------\n *\n *                          FONT BAKING\n *\n * --------------------------------------------------------------*/\nstruct nk_font_bake_data {\n    struct stbtt_fontinfo info;\n    struct stbrp_rect *rects;\n    stbtt_pack_range *ranges;\n    nk_rune range_count;\n};\n\nstruct nk_font_baker {\n    struct nk_allocator alloc;\n    struct stbtt_pack_context spc;\n    struct nk_font_bake_data *build;\n    stbtt_packedchar *packed_chars;\n    struct stbrp_rect *rects;\n    stbtt_pack_range *ranges;\n};\n\nNK_GLOBAL const nk_size nk_rect_align = NK_ALIGNOF(struct stbrp_rect);\nNK_GLOBAL const nk_size nk_range_align = NK_ALIGNOF(stbtt_pack_range);\nNK_GLOBAL const nk_size nk_char_align = NK_ALIGNOF(stbtt_packedchar);\nNK_GLOBAL const nk_size nk_build_align = NK_ALIGNOF(struct nk_font_bake_data);\nNK_GLOBAL const nk_size nk_baker_align = NK_ALIGNOF(struct nk_font_baker);\n\nNK_INTERN int\nnk_range_count(const nk_rune *range)\n{\n    const nk_rune *iter = range;\n    NK_ASSERT(range);\n    if (!range) return 0;\n    while (*(iter++) != 0);\n    return (iter == range) ? 0 : (int)((iter - range)/2);\n}\nNK_INTERN int\nnk_range_glyph_count(const nk_rune *range, int count)\n{\n    int i = 0;\n    int total_glyphs = 0;\n    for (i = 0; i < count; ++i) {\n        int diff;\n        nk_rune f = range[(i*2)+0];\n        nk_rune t = range[(i*2)+1];\n        NK_ASSERT(t >= f);\n        diff = (int)((t - f) + 1);\n        total_glyphs += diff;\n    }\n    return total_glyphs;\n}\nNK_API const nk_rune*\nnk_font_default_glyph_ranges(void)\n{\n    NK_STORAGE const nk_rune ranges[] = {0x0020, 0x00FF, 0};\n    return ranges;\n}\nNK_API const nk_rune*\nnk_font_chinese_glyph_ranges(void)\n{\n    NK_STORAGE const nk_rune ranges[] = {\n        0x0020, 0x00FF,\n        0x3000, 0x30FF,\n        0x31F0, 0x31FF,\n        0xFF00, 0xFFEF,\n        0x4E00, 0x9FAF,\n        0\n    };\n    return ranges;\n}\nNK_API const nk_rune*\nnk_font_cyrillic_glyph_ranges(void)\n{\n    NK_STORAGE const nk_rune ranges[] = {\n        0x0020, 0x00FF,\n        0x0400, 0x052F,\n        0x2DE0, 0x2DFF,\n        0xA640, 0xA69F,\n        0\n    };\n    return ranges;\n}\nNK_API const nk_rune*\nnk_font_korean_glyph_ranges(void)\n{\n    NK_STORAGE const nk_rune ranges[] = {\n        0x0020, 0x00FF,\n        0x3131, 0x3163,\n        0xAC00, 0xD79D,\n        0\n    };\n    return ranges;\n}\nNK_INTERN void\nnk_font_baker_memory(nk_size *temp, int *glyph_count,\n    struct nk_font_config *config_list, int count)\n{\n    int range_count = 0;\n    int total_range_count = 0;\n    struct nk_font_config *iter, *i;\n\n    NK_ASSERT(config_list);\n    NK_ASSERT(glyph_count);\n    if (!config_list) {\n        *temp = 0;\n        *glyph_count = 0;\n        return;\n    }\n    *glyph_count = 0;\n    for (iter = config_list; iter; iter = iter->next) {\n        i = iter;\n        do {if (!i->range) iter->range = nk_font_default_glyph_ranges();\n            range_count = nk_range_count(i->range);\n            total_range_count += range_count;\n            *glyph_count += nk_range_glyph_count(i->range, range_count);\n        } while ((i = i->n) != iter);\n    }\n    *temp = (nk_size)*glyph_count * sizeof(struct stbrp_rect);\n    *temp += (nk_size)total_range_count * sizeof(stbtt_pack_range);\n    *temp += (nk_size)*glyph_count * sizeof(stbtt_packedchar);\n    *temp += (nk_size)count * sizeof(struct nk_font_bake_data);\n    *temp += sizeof(struct nk_font_baker);\n    *temp += nk_rect_align + nk_range_align + nk_char_align;\n    *temp += nk_build_align + nk_baker_align;\n}\nNK_INTERN struct nk_font_baker*\nnk_font_baker(void *memory, int glyph_count, int count, const struct nk_allocator *alloc)\n{\n    struct nk_font_baker *baker;\n    if (!memory) return 0;\n    /* setup baker inside a memory block  */\n    baker = (struct nk_font_baker*)NK_ALIGN_PTR(memory, nk_baker_align);\n    baker->build = (struct nk_font_bake_data*)NK_ALIGN_PTR((baker + 1), nk_build_align);\n    baker->packed_chars = (stbtt_packedchar*)NK_ALIGN_PTR((baker->build + count), nk_char_align);\n    baker->rects = (struct stbrp_rect*)NK_ALIGN_PTR((baker->packed_chars + glyph_count), nk_rect_align);\n    baker->ranges = (stbtt_pack_range*)NK_ALIGN_PTR((baker->rects + glyph_count), nk_range_align);\n    baker->alloc = *alloc;\n    return baker;\n}\nNK_INTERN int\nnk_font_bake_pack(struct nk_font_baker *baker,\n    nk_size *image_memory, int *width, int *height, struct nk_recti *custom,\n    const struct nk_font_config *config_list, int count,\n    const struct nk_allocator *alloc)\n{\n    NK_STORAGE const nk_size max_height = 1024 * 32;\n    const struct nk_font_config *config_iter, *it;\n    int total_glyph_count = 0;\n    int total_range_count = 0;\n    int range_count = 0;\n    int i = 0;\n\n    NK_ASSERT(image_memory);\n    NK_ASSERT(width);\n    NK_ASSERT(height);\n    NK_ASSERT(config_list);\n    NK_ASSERT(count);\n    NK_ASSERT(alloc);\n\n    if (!image_memory || !width || !height || !config_list || !count) return nk_false;\n    for (config_iter = config_list; config_iter; config_iter = config_iter->next) {\n        it = config_iter;\n        do {range_count = nk_range_count(it->range);\n            total_range_count += range_count;\n            total_glyph_count += nk_range_glyph_count(it->range, range_count);\n        } while ((it = it->n) != config_iter);\n    }\n    /* setup font baker from temporary memory */\n    for (config_iter = config_list; config_iter; config_iter = config_iter->next) {\n        it = config_iter;\n        do {\n            struct stbtt_fontinfo *font_info = &baker->build[i++].info;\n            font_info->userdata = (void*)alloc;\n\n            if (!stbtt_InitFont(font_info, (const unsigned char*)it->ttf_blob, stbtt_GetFontOffsetForIndex((const unsigned char*)it->ttf_blob, 0)))\n                return nk_false;\n        } while ((it = it->n) != config_iter);\n    }\n    *height = 0;\n    *width = (total_glyph_count > 1000) ? 1024 : 512;\n    stbtt_PackBegin(&baker->spc, 0, (int)*width, (int)max_height, 0, 1, (void*)alloc);\n    {\n        int input_i = 0;\n        int range_n = 0;\n        int rect_n = 0;\n        int char_n = 0;\n\n        if (custom) {\n            /* pack custom user data first so it will be in the upper left corner*/\n            struct stbrp_rect custom_space;\n            nk_zero(&custom_space, sizeof(custom_space));\n            custom_space.w = (stbrp_coord)(custom->w);\n            custom_space.h = (stbrp_coord)(custom->h);\n\n            stbtt_PackSetOversampling(&baker->spc, 1, 1);\n            stbrp_pack_rects((struct stbrp_context*)baker->spc.pack_info, &custom_space, 1);\n            *height = NK_MAX(*height, (int)(custom_space.y + custom_space.h));\n\n            custom->x = (short)custom_space.x;\n            custom->y = (short)custom_space.y;\n            custom->w = (short)custom_space.w;\n            custom->h = (short)custom_space.h;\n        }\n\n        /* first font pass: pack all glyphs */\n        for (input_i = 0, config_iter = config_list; input_i < count && config_iter;\n            config_iter = config_iter->next) {\n            it = config_iter;\n            do {int n = 0;\n                int glyph_count;\n                const nk_rune *in_range;\n                const struct nk_font_config *cfg = it;\n                struct nk_font_bake_data *tmp = &baker->build[input_i++];\n\n                /* count glyphs + ranges in current font */\n                glyph_count = 0; range_count = 0;\n                for (in_range = cfg->range; in_range[0] && in_range[1]; in_range += 2) {\n                    glyph_count += (int)(in_range[1] - in_range[0]) + 1;\n                    range_count++;\n                }\n\n                /* setup ranges  */\n                tmp->ranges = baker->ranges + range_n;\n                tmp->range_count = (nk_rune)range_count;\n                range_n += range_count;\n                for (i = 0; i < range_count; ++i) {\n                    in_range = &cfg->range[i * 2];\n                    tmp->ranges[i].font_size = cfg->size;\n                    tmp->ranges[i].first_unicode_codepoint_in_range = (int)in_range[0];\n                    tmp->ranges[i].num_chars = (int)(in_range[1]- in_range[0]) + 1;\n                    tmp->ranges[i].chardata_for_range = baker->packed_chars + char_n;\n                    char_n += tmp->ranges[i].num_chars;\n                }\n\n                /* pack */\n                tmp->rects = baker->rects + rect_n;\n                rect_n += glyph_count;\n                stbtt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v);\n                n = stbtt_PackFontRangesGatherRects(&baker->spc, &tmp->info,\n                    tmp->ranges, (int)tmp->range_count, tmp->rects);\n                stbrp_pack_rects((struct stbrp_context*)baker->spc.pack_info, tmp->rects, (int)n);\n\n                /* texture height */\n                for (i = 0; i < n; ++i) {\n                    if (tmp->rects[i].was_packed)\n                        *height = NK_MAX(*height, tmp->rects[i].y + tmp->rects[i].h);\n                }\n            } while ((it = it->n) != config_iter);\n        }\n        NK_ASSERT(rect_n == total_glyph_count);\n        NK_ASSERT(char_n == total_glyph_count);\n        NK_ASSERT(range_n == total_range_count);\n    }\n    *height = (int)nk_round_up_pow2((nk_uint)*height);\n    *image_memory = (nk_size)(*width) * (nk_size)(*height);\n    return nk_true;\n}\nNK_INTERN void\nnk_font_bake(struct nk_font_baker *baker, void *image_memory, int width, int height,\n    struct nk_font_glyph *glyphs, int glyphs_count,\n    const struct nk_font_config *config_list, int font_count)\n{\n    int input_i = 0;\n    nk_rune glyph_n = 0;\n    const struct nk_font_config *config_iter;\n    const struct nk_font_config *it;\n\n    NK_ASSERT(image_memory);\n    NK_ASSERT(width);\n    NK_ASSERT(height);\n    NK_ASSERT(config_list);\n    NK_ASSERT(baker);\n    NK_ASSERT(font_count);\n    NK_ASSERT(glyphs_count);\n    if (!image_memory || !width || !height || !config_list ||\n        !font_count || !glyphs || !glyphs_count)\n        return;\n\n    /* second font pass: render glyphs */\n    nk_zero(image_memory, (nk_size)((nk_size)width * (nk_size)height));\n    baker->spc.pixels = (unsigned char*)image_memory;\n    baker->spc.height = (int)height;\n    for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter;\n        config_iter = config_iter->next) {\n        it = config_iter;\n        do {const struct nk_font_config *cfg = it;\n            struct nk_font_bake_data *tmp = &baker->build[input_i++];\n            stbtt_PackSetOversampling(&baker->spc, cfg->oversample_h, cfg->oversample_v);\n            stbtt_PackFontRangesRenderIntoRects(&baker->spc, &tmp->info, tmp->ranges, (int)tmp->range_count, tmp->rects);\n        } while ((it = it->n) != config_iter);\n    } stbtt_PackEnd(&baker->spc);\n\n    /* third pass: setup font and glyphs */\n    for (input_i = 0, config_iter = config_list; input_i < font_count && config_iter;\n        config_iter = config_iter->next) {\n        it = config_iter;\n        do {nk_size i = 0;\n            int char_idx = 0;\n            nk_rune glyph_count = 0;\n            const struct nk_font_config *cfg = it;\n            struct nk_font_bake_data *tmp = &baker->build[input_i++];\n            struct nk_baked_font *dst_font = cfg->font;\n\n            float font_scale = stbtt_ScaleForPixelHeight(&tmp->info, cfg->size);\n            int unscaled_ascent, unscaled_descent, unscaled_line_gap;\n            stbtt_GetFontVMetrics(&tmp->info, &unscaled_ascent, &unscaled_descent,\n                                    &unscaled_line_gap);\n\n            /* fill baked font */\n            if (!cfg->merge_mode) {\n                dst_font->ranges = cfg->range;\n                dst_font->height = cfg->size;\n                dst_font->ascent = ((float)unscaled_ascent * font_scale);\n                dst_font->descent = ((float)unscaled_descent * font_scale);\n                dst_font->glyph_offset = glyph_n;\n                /*\n                    Need to zero this, or it will carry over from a previous\n                    bake, and cause a segfault when accessing glyphs[].\n                */\n                dst_font->glyph_count = 0;\n            }\n\n            /* fill own baked font glyph array */\n            for (i = 0; i < tmp->range_count; ++i) {\n                stbtt_pack_range *range = &tmp->ranges[i];\n                for (char_idx = 0; char_idx < range->num_chars; char_idx++)\n                {\n                    nk_rune codepoint = 0;\n                    float dummy_x = 0, dummy_y = 0;\n                    stbtt_aligned_quad q;\n                    struct nk_font_glyph *glyph;\n\n                    /* query glyph bounds from stb_truetype */\n                    const stbtt_packedchar *pc = &range->chardata_for_range[char_idx];\n                    codepoint = (nk_rune)(range->first_unicode_codepoint_in_range + char_idx);\n                    stbtt_GetPackedQuad(range->chardata_for_range, (int)width,\n                        (int)height, char_idx, &dummy_x, &dummy_y, &q, 0);\n\n                    /* fill own glyph type with data */\n                    glyph = &glyphs[dst_font->glyph_offset + dst_font->glyph_count + (unsigned int)glyph_count];\n                    glyph->codepoint = codepoint;\n                    glyph->x0 = q.x0; glyph->y0 = q.y0;\n                    glyph->x1 = q.x1; glyph->y1 = q.y1;\n                    glyph->y0 += (dst_font->ascent + 0.5f);\n                    glyph->y1 += (dst_font->ascent + 0.5f);\n                    glyph->w = glyph->x1 - glyph->x0 + 0.5f;\n                    glyph->h = glyph->y1 - glyph->y0;\n\n                    if (cfg->coord_type == NK_COORD_PIXEL) {\n                        glyph->u0 = q.s0 * (float)width;\n                        glyph->v0 = q.t0 * (float)height;\n                        glyph->u1 = q.s1 * (float)width;\n                        glyph->v1 = q.t1 * (float)height;\n                    } else {\n                        glyph->u0 = q.s0;\n                        glyph->v0 = q.t0;\n                        glyph->u1 = q.s1;\n                        glyph->v1 = q.t1;\n                    }\n                    glyph->xadvance = (pc->xadvance + cfg->spacing.x);\n                    if (cfg->pixel_snap)\n                        glyph->xadvance = (float)(int)(glyph->xadvance + 0.5f);\n                    glyph_count++;\n                }\n            }\n            dst_font->glyph_count += glyph_count;\n            glyph_n += glyph_count;\n        } while ((it = it->n) != config_iter);\n    }\n}\nNK_INTERN void\nnk_font_bake_custom_data(void *img_memory, int img_width, int img_height,\n    struct nk_recti img_dst, const char *texture_data_mask, int tex_width,\n    int tex_height, char white, char black)\n{\n    nk_byte *pixels;\n    int y = 0;\n    int x = 0;\n    int n = 0;\n\n    NK_ASSERT(img_memory);\n    NK_ASSERT(img_width);\n    NK_ASSERT(img_height);\n    NK_ASSERT(texture_data_mask);\n    NK_UNUSED(tex_height);\n    if (!img_memory || !img_width || !img_height || !texture_data_mask)\n        return;\n\n    pixels = (nk_byte*)img_memory;\n    for (y = 0, n = 0; y < tex_height; ++y) {\n        for (x = 0; x < tex_width; ++x, ++n) {\n            const int off0 = ((img_dst.x + x) + (img_dst.y + y) * img_width);\n            const int off1 = off0 + 1 + tex_width;\n            pixels[off0] = (texture_data_mask[n] == white) ? 0xFF : 0x00;\n            pixels[off1] = (texture_data_mask[n] == black) ? 0xFF : 0x00;\n        }\n    }\n}\nNK_INTERN void\nnk_font_bake_convert(void *out_memory, int img_width, int img_height,\n    const void *in_memory)\n{\n    int n = 0;\n    nk_rune *dst;\n    const nk_byte *src;\n\n    NK_ASSERT(out_memory);\n    NK_ASSERT(in_memory);\n    NK_ASSERT(img_width);\n    NK_ASSERT(img_height);\n    if (!out_memory || !in_memory || !img_height || !img_width) return;\n\n    dst = (nk_rune*)out_memory;\n    src = (const nk_byte*)in_memory;\n    for (n = (int)(img_width * img_height); n > 0; n--)\n        *dst++ = ((nk_rune)(*src++) << 24) | 0x00FFFFFF;\n}\n\n/* -------------------------------------------------------------\n *\n *                          FONT\n *\n * --------------------------------------------------------------*/\nNK_INTERN float\nnk_font_text_width(nk_handle handle, float height, const char *text, int len)\n{\n    nk_rune unicode;\n    int text_len  = 0;\n    float text_width = 0;\n    int glyph_len = 0;\n    float scale = 0;\n\n    struct nk_font *font = (struct nk_font*)handle.ptr;\n    NK_ASSERT(font);\n    NK_ASSERT(font->glyphs);\n    if (!font || !text || !len)\n        return 0;\n\n    scale = height/font->info.height;\n    glyph_len = text_len = nk_utf_decode(text, &unicode, (int)len);\n    if (!glyph_len) return 0;\n    while (text_len <= (int)len && glyph_len) {\n        const struct nk_font_glyph *g;\n        if (unicode == NK_UTF_INVALID) break;\n\n        /* query currently drawn glyph information */\n        g = nk_font_find_glyph(font, unicode);\n        text_width += g->xadvance * scale;\n\n        /* offset next glyph */\n        glyph_len = nk_utf_decode(text + text_len, &unicode, (int)len - text_len);\n        text_len += glyph_len;\n    }\n    return text_width;\n}\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\nNK_INTERN void\nnk_font_query_font_glyph(nk_handle handle, float height,\n    struct nk_user_font_glyph *glyph, nk_rune codepoint, nk_rune next_codepoint)\n{\n    float scale;\n    const struct nk_font_glyph *g;\n    struct nk_font *font;\n\n    NK_ASSERT(glyph);\n    NK_UNUSED(next_codepoint);\n\n    font = (struct nk_font*)handle.ptr;\n    NK_ASSERT(font);\n    NK_ASSERT(font->glyphs);\n    if (!font || !glyph)\n        return;\n\n    scale = height/font->info.height;\n    g = nk_font_find_glyph(font, codepoint);\n    glyph->width = (g->x1 - g->x0) * scale;\n    glyph->height = (g->y1 - g->y0) * scale;\n    glyph->offset = nk_vec2(g->x0 * scale, g->y0 * scale);\n    glyph->xadvance = (g->xadvance * scale);\n    glyph->uv[0] = nk_vec2(g->u0, g->v0);\n    glyph->uv[1] = nk_vec2(g->u1, g->v1);\n}\n#endif\nNK_API const struct nk_font_glyph*\nnk_font_find_glyph(const struct nk_font *font, nk_rune unicode)\n{\n    int i = 0;\n    int count;\n    int total_glyphs = 0;\n    const struct nk_font_glyph *glyph = 0;\n    const struct nk_font_config *iter = 0;\n\n    NK_ASSERT(font);\n    NK_ASSERT(font->glyphs);\n    NK_ASSERT(font->info.ranges);\n    if (!font || !font->glyphs) return 0;\n\n    glyph = font->fallback;\n    iter = font->config;\n    do {count = nk_range_count(iter->range);\n        for (i = 0; i < count; ++i) {\n            nk_rune f = iter->range[(i*2)+0];\n            nk_rune t = iter->range[(i*2)+1];\n            int diff = (int)((t - f) + 1);\n            if (unicode >= f && unicode <= t)\n                return &font->glyphs[((nk_rune)total_glyphs + (unicode - f))];\n            total_glyphs += diff;\n        }\n    } while ((iter = iter->n) != font->config);\n    return glyph;\n}\nNK_INTERN void\nnk_font_init(struct nk_font *font, float pixel_height,\n    nk_rune fallback_codepoint, struct nk_font_glyph *glyphs,\n    const struct nk_baked_font *baked_font, nk_handle atlas)\n{\n    struct nk_baked_font baked;\n    NK_ASSERT(font);\n    NK_ASSERT(glyphs);\n    NK_ASSERT(baked_font);\n    if (!font || !glyphs || !baked_font)\n        return;\n\n    baked = *baked_font;\n    font->fallback = 0;\n    font->info = baked;\n    font->scale = (float)pixel_height / (float)font->info.height;\n    font->glyphs = &glyphs[baked_font->glyph_offset];\n    font->texture = atlas;\n    font->fallback_codepoint = fallback_codepoint;\n    font->fallback = nk_font_find_glyph(font, fallback_codepoint);\n\n    font->handle.height = font->info.height * font->scale;\n    font->handle.width = nk_font_text_width;\n    font->handle.userdata.ptr = font;\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n    font->handle.query = nk_font_query_font_glyph;\n    font->handle.texture = font->texture;\n#endif\n}\n\n/* ---------------------------------------------------------------------------\n *\n *                          DEFAULT FONT\n *\n * ProggyClean.ttf\n * Copyright (c) 2004, 2005 Tristan Grimmer\n * MIT license https://github.com/bluescan/proggyfonts/blob/master/LICENSE\n * Download and more information at https://github.com/bluescan/proggyfonts\n *-----------------------------------------------------------------------------*/\n#ifdef __clang__\n#pragma clang diagnostic push\n#pragma clang diagnostic ignored \"-Woverlength-strings\"\n#elif defined(__GNUC__) || defined(__GNUG__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Woverlength-strings\"\n#endif\n\n#ifdef NK_INCLUDE_DEFAULT_FONT\n\nNK_GLOBAL const char nk_proggy_clean_ttf_compressed_data_base85[11980+1] =\n    \"7])#######hV0qs'/###[),##/l:$#Q6>##5[n42>c-TH`->>#/e>11NNV=Bv(*:.F?uu#(gRU.o0XGH`$vhLG1hxt9?W`#,5LsCp#-i>.r$<$6pD>Lb';9Crc6tgXmKVeU2cD4Eo3R/\"\n    \"2*>]b(MC;$jPfY.;h^`IWM9<Lh2TlS+f-s$o6Q<BWH`YiU.xfLq$N;$0iR/GX:U(jcW2p/W*q?-qmnUCI;jHSAiFWM.R*kU@C=GH?a9wp8f$e.-4^Qg1)Q-GL(lf(r/7GrRgwV%MS=C#\"\n    \"`8ND>Qo#t'X#(v#Y9w0#1D$CIf;W'#pWUPXOuxXuU(H9M(1<q-UE31#^-V'8IRUo7Qf./L>=Ke$$'5F%)]0^#0X@U.a<r:QLtFsLcL6##lOj)#.Y5<-R&KgLwqJfLgN&;Q?gI^#DY2uL\"\n    \"i@^rMl9t=cWq6##weg>$FBjVQTSDgEKnIS7EM9>ZY9w0#L;>>#Mx&4Mvt//L[MkA#W@lK.N'[0#7RL_&#w+F%HtG9M#XL`N&.,GM4Pg;-<nLENhvx>-VsM.M0rJfLH2eTM`*oJMHRC`N\"\n    \"kfimM2J,W-jXS:)r0wK#@Fge$U>`w'N7G#$#fB#$E^$#:9:hk+eOe--6x)F7*E%?76%^GMHePW-Z5l'&GiF#$956:rS?dA#fiK:)Yr+`&#0j@'DbG&#^$PG.Ll+DNa<XCMKEV*N)LN/N\"\n    \"*b=%Q6pia-Xg8I$<MR&,VdJe$<(7G;Ckl'&hF;;$<_=X(b.RS%%)###MPBuuE1V:v&cX&#2m#(&cV]`k9OhLMbn%s$G2,B$BfD3X*sp5#l,$R#]x_X1xKX%b5U*[r5iMfUo9U`N99hG)\"\n    \"tm+/Us9pG)XPu`<0s-)WTt(gCRxIg(%6sfh=ktMKn3j)<6<b5Sk_/0(^]AaN#(p/L>&VZ>1i%h1S9u5o@YaaW$e+b<TWFn/Z:Oh(Cx2$lNEoN^e)#CFY@@I;BOQ*sRwZtZxRcU7uW6CX\"\n    \"ow0i(?$Q[cjOd[P4d)]>ROPOpxTO7Stwi1::iB1q)C_=dV26J;2,]7op$]uQr@_V7$q^%lQwtuHY]=DX,n3L#0PHDO4f9>dC@O>HBuKPpP*E,N+b3L#lpR/MrTEH.IAQk.a>D[.e;mc.\"\n    \"x]Ip.PH^'/aqUO/$1WxLoW0[iLA<QT;5HKD+@qQ'NQ(3_PLhE48R.qAPSwQ0/WK?Z,[x?-J;jQTWA0X@KJ(_Y8N-:/M74:/-ZpKrUss?d#dZq]DAbkU*JqkL+nwX@@47`5>w=4h(9.`G\"\n    \"CRUxHPeR`5Mjol(dUWxZa(>STrPkrJiWx`5U7F#.g*jrohGg`cg:lSTvEY/EV_7H4Q9[Z%cnv;JQYZ5q.l7Zeas:HOIZOB?G<Nald$qs]@]L<J7bR*>gv:[7MI2k).'2($5FNP&EQ(,)\"\n    \"U]W]+fh18.vsai00);D3@4ku5P?DP8aJt+;qUM]=+b'8@;mViBKx0DE[-auGl8:PJ&Dj+M6OC]O^((##]`0i)drT;-7X`=-H3[igUnPG-NZlo.#k@h#=Ork$m>a>$-?Tm$UV(?#P6YY#\"\n    \"'/###xe7q.73rI3*pP/$1>s9)W,JrM7SN]'/4C#v$U`0#V.[0>xQsH$fEmPMgY2u7Kh(G%siIfLSoS+MK2eTM$=5,M8p`A.;_R%#u[K#$x4AG8.kK/HSB==-'Ie/QTtG?-.*^N-4B/ZM\"\n    \"_3YlQC7(p7q)&](`6_c)$/*JL(L-^(]$wIM`dPtOdGA,U3:w2M-0<q-]L_?^)1vw'.,MRsqVr.L;aN&#/EgJ)PBc[-f>+WomX2u7lqM2iEumMTcsF?-aT=Z-97UEnXglEn1K-bnEO`gu\"\n    \"Ft(c%=;Am_Qs@jLooI&NX;]0#j4#F14;gl8-GQpgwhrq8'=l_f-b49'UOqkLu7-##oDY2L(te+Mch&gLYtJ,MEtJfLh'x'M=$CS-ZZ%P]8bZ>#S?YY#%Q&q'3^Fw&?D)UDNrocM3A76/\"\n    \"/oL?#h7gl85[qW/NDOk%16ij;+:1a'iNIdb-ou8.P*w,v5#EI$TWS>Pot-R*H'-SEpA:g)f+O$%%`kA#G=8RMmG1&O`>to8bC]T&$,n.LoO>29sp3dt-52U%VM#q7'DHpg+#Z9%H[K<L\"\n    \"%a2E-grWVM3@2=-k22tL]4$##6We'8UJCKE[d_=%wI;'6X-GsLX4j^SgJ$##R*w,vP3wK#iiW&#*h^D&R?jp7+/u&#(AP##XU8c$fSYW-J95_-Dp[g9wcO&#M-h1OcJlc-*vpw0xUX&#\"\n    \"OQFKNX@QI'IoPp7nb,QU//MQ&ZDkKP)X<WSVL(68uVl&#c'[0#(s1X&xm$Y%B7*K:eDA323j998GXbA#pwMs-jgD$9QISB-A_(aN4xoFM^@C58D0+Q+q3n0#3U1InDjF682-SjMXJK)(\"\n    \"h$hxua_K]ul92%'BOU&#BRRh-slg8KDlr:%L71Ka:.A;%YULjDPmL<LYs8i#XwJOYaKPKc1h:'9Ke,g)b),78=I39B;xiY$bgGw-&.Zi9InXDuYa%G*f2Bq7mn9^#p1vv%#(Wi-;/Z5h\"\n    \"o;#2:;%d&#x9v68C5g?ntX0X)pT`;%pB3q7mgGN)3%(P8nTd5L7GeA-GL@+%J3u2:(Yf>et`e;)f#Km8&+DC$I46>#Kr]]u-[=99tts1.qb#q72g1WJO81q+eN'03'eM>&1XxY-caEnO\"\n    \"j%2n8)),?ILR5^.Ibn<-X-Mq7[a82Lq:F&#ce+S9wsCK*x`569E8ew'He]h:sI[2LM$[guka3ZRd6:t%IG:;$%YiJ:Nq=?eAw;/:nnDq0(CYcMpG)qLN4$##&J<j$UpK<Q4a1]MupW^-\"\n    \"sj_$%[HK%'F####QRZJ::Y3EGl4'@%FkiAOg#p[##O`gukTfBHagL<LHw%q&OV0##F=6/:chIm0@eCP8X]:kFI%hl8hgO@RcBhS-@Qb$%+m=hPDLg*%K8ln(wcf3/'DW-$.lR?n[nCH-\"\n    \"eXOONTJlh:.RYF%3'p6sq:UIMA945&^HFS87@$EP2iG<-lCO$%c`uKGD3rC$x0BL8aFn--`ke%#HMP'vh1/R&O_J9'um,.<tx[@%wsJk&bUT2`0uMv7gg#qp/ij.L56'hl;.s5CUrxjO\"\n    \"M7-##.l+Au'A&O:-T72L]P`&=;ctp'XScX*rU.>-XTt,%OVU4)S1+R-#dg0/Nn?Ku1^0f$B*P:Rowwm-`0PKjYDDM'3]d39VZHEl4,.j']Pk-M.h^&:0FACm$maq-&sgw0t7/6(^xtk%\"\n    \"LuH88Fj-ekm>GA#_>568x6(OFRl-IZp`&b,_P'$M<Jnq79VsJW/mWS*PUiq76;]/NM_>hLbxfc$mj`,O;&%W2m`Zh:/)Uetw:aJ%]K9h:TcF]u_-Sj9,VK3M.*'&0D[Ca]J9gp8,kAW]\"\n    \"%(?A%R$f<->Zts'^kn=-^@c4%-pY6qI%J%1IGxfLU9CP8cbPlXv);C=b),<2mOvP8up,UVf3839acAWAW-W?#ao/^#%KYo8fRULNd2.>%m]UK:n%r$'sw]J;5pAoO_#2mO3n,'=H5(et\"\n    \"Hg*`+RLgv>=4U8guD$I%D:W>-r5V*%j*W:Kvej.Lp$<M-SGZ':+Q_k+uvOSLiEo(<aD/K<CCc`'Lx>'?;++O'>()jLR-^u68PHm8ZFWe+ej8h:9r6L*0//c&iH&R8pRbA#Kjm%upV1g:\"\n    \"a_#Ur7FuA#(tRh#.Y5K+@?3<-8m0$PEn;J:rh6?I6uG<-`wMU'ircp0LaE_OtlMb&1#6T.#FDKu#1Lw%u%+GM+X'e?YLfjM[VO0MbuFp7;>Q&#WIo)0@F%q7c#4XAXN-U&VB<HFF*qL(\"\n    \"$/V,;(kXZejWO`<[5?\\?ewY(*9=%wDc;,u<'9t3W-(H1th3+G]ucQ]kLs7df($/*JL]@*t7Bu_G3_7mp7<iaQjO@.kLg;x3B0lqp7Hf,^Ze7-##@/c58Mo(3;knp0%)A7?-W+eI'o8)b<\"\n    \"nKnw'Ho8C=Y>pqB>0ie&jhZ[?iLR@@_AvA-iQC(=ksRZRVp7`.=+NpBC%rh&3]R:8XDmE5^V8O(x<<aG/1N$#FX$0V5Y6x'aErI3I$7x%E`v<-BY,)%-?Psf*l?%C3.mM(=/M0:JxG'?\"\n    \"7WhH%o'a<-80g0NBxoO(GH<dM]n.+%q@jH?f.UsJ2Ggs&4<-e47&Kl+f//9@`b+?.TeN_&B8Ss?v;^Trk;f#YvJkl&w$]>-+k?'(<S:68tq*WoDfZu';mM?8X[ma8W%*`-=;D.(nc7/;\"\n    \")g:T1=^J$&BRV(-lTmNB6xqB[@0*o.erM*<SWF]u2=st-*(6v>^](H.aREZSi,#1:[IXaZFOm<-ui#qUq2$##Ri;u75OK#(RtaW-K-F`S+cF]uN`-KMQ%rP/Xri.LRcB##=YL3BgM/3M\"\n    \"D?@f&1'BW-)Ju<L25gl8uhVm1hL$##*8###'A3/LkKW+(^rWX?5W_8g)a(m&K8P>#bmmWCMkk&#TR`C,5d>g)F;t,4:@_l8G/5h4vUd%&%950:VXD'QdWoY-F$BtUwmfe$YqL'8(PWX(\"\n    \"P?^@Po3$##`MSs?DWBZ/S>+4%>fX,VWv/w'KD`LP5IbH;rTV>n3cEK8U#bX]l-/V+^lj3;vlMb&[5YQ8#pekX9JP3XUC72L,,?+Ni&co7ApnO*5NK,((W-i:$,kp'UDAO(G0Sq7MVjJs\"\n    \"bIu)'Z,*[>br5fX^:FPAWr-m2KgL<LUN098kTF&#lvo58=/vjDo;.;)Ka*hLR#/k=rKbxuV`>Q_nN6'8uTG&#1T5g)uLv:873UpTLgH+#FgpH'_o1780Ph8KmxQJ8#H72L4@768@Tm&Q\"\n    \"h4CB/5OvmA&,Q&QbUoi$a_%3M01H)4x7I^&KQVgtFnV+;[Pc>[m4k//,]1?#`VY[Jr*3&&slRfLiVZJ:]?=K3Sw=[$=uRB?3xk48@aeg<Z'<$#4H)6,>e0jT6'N#(q%.O=?2S]u*(m<-\"\n    \"V8J'(1)G][68hW$5'q[GC&5j`TE?m'esFGNRM)j,ffZ?-qx8;->g4t*:CIP/[Qap7/9'#(1sao7w-.qNUdkJ)tCF&#B^;xGvn2r9FEPFFFcL@.iFNkTve$m%#QvQS8U@)2Z+3K:AKM5i\"\n    \"sZ88+dKQ)W6>J%CL<KE>`.d*(B`-n8D9oK<Up]c$X$(,)M8Zt7/[rdkqTgl-0cuGMv'?>-XV1q['-5k'cAZ69e;D_?$ZPP&s^+7])$*$#@QYi9,5P&#9r+$%CE=68>K8r0=dSC%%(@p7\"\n    \".m7jilQ02'0-VWAg<a/''3u.=4L$Y)6k/K:_[3=&jvL<L0C/2'v:^;-DIBW,B4E68:kZ;%?8(Q8BH=kO65BW?xSG&#@uU,DS*,?.+(o(#1vCS8#CHF>TlGW'b)Tq7VT9q^*^$$.:&N@@\"\n    \"$&)WHtPm*5_rO0&e%K&#-30j(E4#'Zb.o/(Tpm$>K'f@[PvFl,hfINTNU6u'0pao7%XUp9]5.>%h`8_=VYbxuel.NTSsJfLacFu3B'lQSu/m6-Oqem8T+oE--$0a/k]uj9EwsG>%veR*\"\n    \"hv^BFpQj:K'#SJ,sB-'#](j.Lg92rTw-*n%@/;39rrJF,l#qV%OrtBeC6/,;qB3ebNW[?,Hqj2L.1NP&GjUR=1D8QaS3Up&@*9wP?+lo7b?@%'k4`p0Z$22%K3+iCZj?XJN4Nm&+YF]u\"\n    \"@-W$U%VEQ/,,>>#)D<h#`)h0:<Q6909ua+&VU%n2:cG3FJ-%@Bj-DgLr`Hw&HAKjKjseK</xKT*)B,N9X3]krc12t'pgTV(Lv-tL[xg_%=M_q7a^x?7Ubd>#%8cY#YZ?=,`Wdxu/ae&#\"\n    \"w6)R89tI#6@s'(6Bf7a&?S=^ZI_kS&ai`&=tE72L_D,;^R)7[$s<Eh#c&)q.MXI%#v9ROa5FZO%sF7q7Nwb&#ptUJ:aqJe$Sl68%.D###EC><?-aF&#RNQv>o8lKN%5/$(vdfq7+ebA#\"\n    \"u1p]ovUKW&Y%q]'>$1@-[xfn$7ZTp7mM,G,Ko7a&Gu%G[RMxJs[0MM%wci.LFDK)(<c`Q8N)jEIF*+?P2a8g%)$q]o2aH8C&<SibC/q,(e:v;-b#6[$NtDZ84Je2KNvB#$P5?tQ3nt(0\"\n    \"d=j.LQf./Ll33+(;q3L-w=8dX$#WF&uIJ@-bfI>%:_i2B5CsR8&9Z&#=mPEnm0f`<&c)QL5uJ#%u%lJj+D-r;BoF&#4DoS97h5g)E#o:&S4weDF,9^Hoe`h*L+_a*NrLW-1pG_&2UdB8\"\n    \"6e%B/:=>)N4xeW.*wft-;$'58-ESqr<b?UI(_%@[P46>#U`'6AQ]m&6/`Z>#S?YY#Vc;r7U2&326d=w&H####?TZ`*4?&.MK?LP8Vxg>$[QXc%QJv92.(Db*B)gb*BM9dM*hJMAo*c&#\"\n    \"b0v=Pjer]$gG&JXDf->'StvU7505l9$AFvgYRI^&<^b68?j#q9QX4SM'RO#&sL1IM.rJfLUAj221]d##DW=m83u5;'bYx,*Sl0hL(W;;$doB&O/TQ:(Z^xBdLjL<Lni;''X.`$#8+1GD\"\n    \":k$YUWsbn8ogh6rxZ2Z9]%nd+>V#*8U_72Lh+2Q8Cj0i:6hp&$C/:p(HK>T8Y[gHQ4`4)'$Ab(Nof%V'8hL&#<NEdtg(n'=S1A(Q1/I&4([%dM`,Iu'1:_hL>SfD07&6D<fp8dHM7/g+\"\n    \"tlPN9J*rKaPct&?'uBCem^jn%9_K)<,C5K3s=5g&GmJb*[SYq7K;TRLGCsM-$$;S%:Y@r7AK0pprpL<Lrh,q7e/%KWK:50I^+m'vi`3?%Zp+<-d+$L-Sv:@.o19n$s0&39;kn;S%BSq*\"\n    \"$3WoJSCLweV[aZ'MQIjO<7;X-X;&+dMLvu#^UsGEC9WEc[X(wI7#2.(F0jV*eZf<-Qv3J-c+J5AlrB#$p(H68LvEA'q3n0#m,[`*8Ft)FcYgEud]CWfm68,(aLA$@EFTgLXoBq/UPlp7\"\n    \":d[/;r_ix=:TF`S5H-b<LI&HY(K=h#)]Lk$K14lVfm:x$H<3^Ql<M`$OhapBnkup'D#L$Pb_`N*g]2e;X/Dtg,bsj&K#2[-:iYr'_wgH)NUIR8a1n#S?Yej'h8^58UbZd+^FKD*T@;6A\"\n    \"7aQC[K8d-(v6GI$x:T<&'Gp5Uf>@M.*J:;$-rv29'M]8qMv-tLp,'886iaC=Hb*YJoKJ,(j%K=H`K.v9HggqBIiZu'QvBT.#=)0ukruV&.)3=(^1`o*Pj4<-<aN((^7('#Z0wK#5GX@7\"\n    \"u][`*S^43933A4rl][`*O4CgLEl]v$1Q3AeF37dbXk,.)vj#x'd`;qgbQR%FW,2(?LO=s%Sc68%NP'##Aotl8x=BE#j1UD([3$M(]UI2LX3RpKN@;/#f'f/&_mt&F)XdF<9t4)Qa.*kT\"\n    \"LwQ'(TTB9.xH'>#MJ+gLq9-##@HuZPN0]u:h7.T..G:;$/Usj(T7`Q8tT72LnYl<-qx8;-HV7Q-&Xdx%1a,hC=0u+HlsV>nuIQL-5<N?)NBS)QN*_I,?&)2'IM%L3I)X((e/dl2&8'<M\"\n    \":^#M*Q+[T.Xri.LYS3v%fF`68h;b-X[/En'CR.q7E)p'/kle2HM,u;^%OKC-N+Ll%F9CF<Nf'^#t2L,;27W:0O@6##U6W7:$rJfLWHj$#)woqBefIZ.PK<b*t7ed;p*_m;4ExK#h@&]>\"\n    \"_>@kXQtMacfD.m-VAb8;IReM3$wf0''hra*so568'Ip&vRs849'MRYSp%:t:h5qSgwpEr$B>Q,;s(C#$)`svQuF$##-D,##,g68@2[T;.XSdN9Qe)rpt._K-#5wF)sP'##p#C0c%-Gb%\"\n    \"hd+<-j'Ai*x&&HMkT]C'OSl##5RG[JXaHN;d'uA#x._U;.`PU@(Z3dt4r152@:v,'R.Sj'w#0<-;kPI)FfJ&#AYJ&#//)>-k=m=*XnK$>=)72L]0I%>.G690a:$##<,);?;72#?x9+d;\"\n    \"^V'9;jY@;)br#q^YQpx:X#Te$Z^'=-=bGhLf:D6&bNwZ9-ZD#n^9HhLMr5G;']d&6'wYmTFmL<LD)F^%[tC'8;+9E#C$g%#5Y>q9wI>P(9mI[>kC-ekLC/R&CH+s'B;K-M6$EB%is00:\"\n    \"+A4[7xks.LrNk0&E)wILYF@2L'0Nb$+pv<(2.768/FrY&h$^3i&@+G%JT'<-,v`3;_)I9M^AE]CN?Cl2AZg+%4iTpT3<n-&%H%b<FDj2M<hH=&Eh<2Len$b*aTX=-8QxN)k11IM1c^j%\"\n    \"9s<L<NFSo)B?+<-(GxsF,^-Eh@$4dXhN$+#rxK8'je'D7k`e;)2pYwPA'_p9&@^18ml1^[@g4t*[JOa*[=Qp7(qJ_oOL^('7fB&Hq-:sf,sNj8xq^>$U4O]GKx'm9)b@p7YsvK3w^YR-\"\n    \"CdQ*:Ir<($u&)#(&?L9Rg3H)4fiEp^iI9O8KnTj,]H?D*r7'M;PwZ9K0E^k&-cpI;.p/6_vwoFMV<->#%Xi.LxVnrU(4&8/P+:hLSKj$#U%]49t'I:rgMi'FL@a:0Y-uA[39',(vbma*\"\n    \"hU%<-SRF`Tt:542R_VV$p@[p8DV[A,?1839FWdF<TddF<9Ah-6&9tWoDlh]&1SpGMq>Ti1O*H&#(AL8[_P%.M>v^-))qOT*F5Cq0`Ye%+$B6i:7@0IX<N+T+0MlMBPQ*Vj>SsD<U4JHY\"\n    \"8kD2)2fU/M#$e.)T4,_=8hLim[&);?UkK'-x?'(:siIfL<$pFM`i<?%W(mGDHM%>iWP,##P`%/L<eXi:@Z9C.7o=@(pXdAO/NLQ8lPl+HPOQa8wD8=^GlPa8TKI1CjhsCTSLJM'/Wl>-\"\n    \"S(qw%sf/@%#B6;/U7K]uZbi^Oc^2n<bhPmUkMw>%t<)'mEVE''n`WnJra$^TKvX5B>;_aSEK',(hwa0:i4G?.Bci.(X[?b*($,=-n<.Q%`(X=?+@Am*Js0&=3bh8K]mL<LoNs'6,'85`\"\n    \"0?t/'_U59@]ddF<#LdF<eWdF<OuN/45rY<-L@&#+fm>69=Lb,OcZV/);TTm8VI;?%OtJ<(b4mq7M6:u?KRdF<gR@2L=FNU-<b[(9c/ML3m;Z[$oF3g)GAWqpARc=<ROu7cL5l;-[A]%/\"\n    \"+fsd;l#SafT/f*W]0=O'$(Tb<[)*@e775R-:Yob%g*>l*:xP?Yb.5)%w_I?7uk5JC+FS(m#i'k.'a0i)9<7b'fs'59hq$*5Uhv##pi^8+hIEBF`nvo`;'l0.^S1<-wUK2/Coh58KKhLj\"\n    \"M=SO*rfO`+qC`W-On.=AJ56>>i2@2LH6A:&5q`?9I3@@'04&p2/LVa*T-4<-i3;M9UvZd+N7>b*eIwg:CC)c<>nO&#<IGe;__.thjZl<%w(Wk2xmp4Q@I#I9,DF]u7-P=.-_:YJ]aS@V\"\n    \"?6*C()dOp7:WL,b&3Rg/.cmM9&r^>$(>.Z-I&J(Q0Hd5Q%7Co-b`-c<N(6r@ip+AurK<m86QIth*#v;-OBqi+L7wDE-Ir8K['m+DDSLwK&/.?-V%U_%3:qKNu$_b*B-kp7NaD'QdWQPK\"\n    \"Yq[@>P)hI;*_F]u`Rb[.j8_Q/<&>uu+VsH$sM9TA%?)(vmJ80),P7E>)tjD%2L=-t#fK[%`v=Q8<FfNkgg^oIbah*#8/Qt$F&:K*-(N/'+1vMB,u()-a.VUU*#[e%gAAO(S>WlA2);Sa\"\n    \">gXm8YB`1d@K#n]76-a$U,mF<fX]idqd)<3,]J7JmW4`6]uks=4-72L(jEk+:bJ0M^q-8Dm_Z?0olP1C9Sa&H[d&c$ooQUj]Exd*3ZM@-WGW2%s',B-_M%>%Ul:#/'xoFM9QX-$.QN'>\"\n    \"[%$Z$uF6pA6Ki2O5:8w*vP1<-1`[G,)-m#>0`P&#eb#.3i)rtB61(o'$?X3B</R90;eZ]%Ncq;-Tl]#F>2Qft^ae_5tKL9MUe9b*sLEQ95C&`=G?@Mj=wh*'3E>=-<)Gt*Iw)'QG:`@I\"\n    \"wOf7&]1i'S01B+Ev/Nac#9S;=;YQpg_6U`*kVY39xK,[/6Aj7:'1Bm-_1EYfa1+o&o4hp7KN_Q(OlIo@S%;jVdn0'1<Vc52=u`3^o-n1'g4v58Hj&6_t7$##?M)c<$bgQ_'SY((-xkA#\"\n    \"Y(,p'H9rIVY-b,'%bCPF7.J<Up^,(dU1VY*5#WkTU>h19w,WQhLI)3S#f$2(eb,jr*b;3Vw]*7NH%$c4Vs,eD9>XW8?N]o+(*pgC%/72LV-u<Hp,3@e^9UB1J+ak9-TN/mhKPg+AJYd$\"\n    \"MlvAF_jCK*.O-^(63adMT->W%iewS8W6m2rtCpo'RS1R84=@paTKt)>=%&1[)*vp'u+x,VrwN;&]kuO9JDbg=pO$J*.jVe;u'm0dr9l,<*wMK*Oe=g8lV_KEBFkO'oU]^=[-792#ok,)\"\n    \"i]lR8qQ2oA8wcRCZ^7w/Njh;?.stX?Q1>S1q4Bn$)K1<-rGdO'$Wr.Lc.CG)$/*JL4tNR/,SVO3,aUw'DJN:)Ss;wGn9A32ijw%FL+Z0Fn.U9;reSq)bmI32U==5ALuG&#Vf1398/pVo\"\n    \"1*c-(aY168o<`JsSbk-,1N;$>0:OUas(3:8Z972LSfF8eb=c-;>SPw7.6hn3m`9^Xkn(r.qS[0;T%&Qc=+STRxX'q1BNk3&*eu2;&8q$&x>Q#Q7^Tf+6<(d%ZVmj2bDi%.3L2n+4W'$P\"\n    \"iDDG)g,r%+?,$@?uou5tSe2aN_AQU*<h`e-GI7)?OK2A.d7_c)?wQ5AS@DL3r#7fSkgl6-++D:'A,uq7SvlB$pcpH'q3n0#_%dY#xCpr-l<F0NR@-##FEV6NTF6##$l84N1w?AO>'IAO\"\n    \"URQ##V^Fv-XFbGM7Fl(N<3DhLGF%q.1rC$#:T__&Pi68%0xi_&[qFJ(77j_&JWoF.V735&T,[R*:xFR*K5>>#`bW-?4Ne_&6Ne_&6Ne_&n`kr-#GJcM6X;uM6X;uM(.a..^2TkL%oR(#\"\n    \";u.T%fAr%4tJ8&><1=GHZ_+m9/#H1F^R#SC#*N=BA9(D?v[UiFY>>^8p,KKF.W]L29uLkLlu/+4T<XoIB&hx=T1PcDaB&;HH+-AFr?(m9HZV)FKS8JCw;SD=6[^/DZUL`EUDf]GGlG&>\"\n    \"w$)F./^n3+rlo+DB;5sIYGNk+i1t-69Jg--0pao7Sm#K)pdHW&;LuDNH@H>#/X-TI(;P>#,Gc>#0Su>#4`1?#8lC?#<xU?#@.i?#D:%@#HF7@#LRI@#P_[@#Tkn@#Xw*A#]-=A#a9OA#\"\n    \"d<F&#*;G##.GY##2Sl##6`($#:l:$#>xL$#B.`$#F:r$#JF.%#NR@%#R_R%#Vke%#Zww%#_-4&#3^Rh%Sflr-k'MS.o?.5/sWel/wpEM0%3'/1)K^f1-d>G21&v(35>V`39V7A4=onx4\"\n    \"A1OY5EI0;6Ibgr6M$HS7Q<)58C5w,;WoA*#[%T*#`1g*#d=#+#hI5+#lUG+#pbY+#tnl+#x$),#&1;,#*=M,#.I`,#2Ur,#6b.-#;w[H#iQtA#m^0B#qjBB#uvTB##-hB#'9$C#+E6C#\"\n    \"/QHC#3^ZC#7jmC#;v)D#?,<D#C8ND#GDaD#KPsD#O]/E#g1A5#KA*1#gC17#MGd;#8(02#L-d3#rWM4#Hga1#,<w0#T.j<#O#'2#CYN1#qa^:#_4m3#o@/=#eG8=#t8J5#`+78#4uI-#\"\n    \"m3B2#SB[8#Q0@8#i[*9#iOn8#1Nm;#^sN9#qh<9#:=x-#P;K2#$%X9#bC+.#Rg;<#mN=.#MTF.#RZO.#2?)4#Y#(/#[)1/#b;L/#dAU/#0Sv;#lY$0#n`-0#sf60#(F24#wrH0#%/e0#\"\n    \"TmD<#%JSMFove:CTBEXI:<eh2g)B,3h2^G3i;#d3jD>)4kMYD4lVu`4m`:&5niUA5@(A5BA1]PBB:xlBCC=2CDLXMCEUtiCf&0g2'tN?PGT4CPGT4CPGT4CPGT4CPGT4CPGT4CPGT4CP\"\n    \"GT4CPGT4CPGT4CPGT4CPGT4CPGT4CP-qekC`.9kEg^+F$kwViFJTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5KTB&5o,^<-28ZI'O?;xp\"\n    \"O?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xpO?;xp;7q-#lLYI:xvD=#\";\n\n#endif /* NK_INCLUDE_DEFAULT_FONT */\n\n#define NK_CURSOR_DATA_W 90\n#define NK_CURSOR_DATA_H 27\nNK_GLOBAL const char nk_custom_cursor_data[NK_CURSOR_DATA_W * NK_CURSOR_DATA_H + 1] =\n{\n    \"..-         -XXXXXXX-    X    -           X           -XXXXXXX          -          XXXXXXX\"\n    \"..-         -X.....X-   X.X   -          X.X          -X.....X          -          X.....X\"\n    \"---         -XXX.XXX-  X...X  -         X...X         -X....X           -           X....X\"\n    \"X           -  X.X  - X.....X -        X.....X        -X...X            -            X...X\"\n    \"XX          -  X.X  -X.......X-       X.......X       -X..X.X           -           X.X..X\"\n    \"X.X         -  X.X  -XXXX.XXXX-       XXXX.XXXX       -X.X X.X          -          X.X X.X\"\n    \"X..X        -  X.X  -   X.X   -          X.X          -XX   X.X         -         X.X   XX\"\n    \"X...X       -  X.X  -   X.X   -    XX    X.X    XX    -      X.X        -        X.X      \"\n    \"X....X      -  X.X  -   X.X   -   X.X    X.X    X.X   -       X.X       -       X.X       \"\n    \"X.....X     -  X.X  -   X.X   -  X..X    X.X    X..X  -        X.X      -      X.X        \"\n    \"X......X    -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -         X.X   XX-XX   X.X         \"\n    \"X.......X   -  X.X  -   X.X   -X.....................X-          X.X X.X-X.X X.X          \"\n    \"X........X  -  X.X  -   X.X   - X...XXXXXX.XXXXXX...X -           X.X..X-X..X.X           \"\n    \"X.........X -XXX.XXX-   X.X   -  X..X    X.X    X..X  -            X...X-X...X            \"\n    \"X..........X-X.....X-   X.X   -   X.X    X.X    X.X   -           X....X-X....X           \"\n    \"X......XXXXX-XXXXXXX-   X.X   -    XX    X.X    XX    -          X.....X-X.....X          \"\n    \"X...X..X    ---------   X.X   -          X.X          -          XXXXXXX-XXXXXXX          \"\n    \"X..X X..X   -       -XXXX.XXXX-       XXXX.XXXX       ------------------------------------\"\n    \"X.X  X..X   -       -X.......X-       X.......X       -    XX           XX    -           \"\n    \"XX    X..X  -       - X.....X -        X.....X        -   X.X           X.X   -           \"\n    \"      X..X          -  X...X  -         X...X         -  X..X           X..X  -           \"\n    \"       XX           -   X.X   -          X.X          - X...XXXXXXXXXXXXX...X -           \"\n    \"------------        -    X    -           X           -X.....................X-           \"\n    \"                    ----------------------------------- X...XXXXXXXXXXXXX...X -           \"\n    \"                                                      -  X..X           X..X  -           \"\n    \"                                                      -   X.X           X.X   -           \"\n    \"                                                      -    XX           XX    -           \"\n};\n\n#ifdef __clang__\n#pragma clang diagnostic pop\n#elif defined(__GNUC__) || defined(__GNUG__)\n#pragma GCC diagnostic pop\n#endif\n\nNK_GLOBAL unsigned char *nk__barrier;\nNK_GLOBAL unsigned char *nk__barrier2;\nNK_GLOBAL unsigned char *nk__barrier3;\nNK_GLOBAL unsigned char *nk__barrier4;\nNK_GLOBAL unsigned char *nk__dout;\n\nNK_INTERN unsigned int\nnk_decompress_length(unsigned char *input)\n{\n    return (unsigned int)((input[8] << 24) + (input[9] << 16) + (input[10] << 8) + input[11]);\n}\nNK_INTERN void\nnk__match(unsigned char *data, unsigned int length)\n{\n    /* INVERSE of memmove... write each byte before copying the next...*/\n    NK_ASSERT (nk__dout + length <= nk__barrier);\n    if (nk__dout + length > nk__barrier) { nk__dout += length; return; }\n    if (data < nk__barrier4) { nk__dout = nk__barrier+1; return; }\n    while (length--) *nk__dout++ = *data++;\n}\nNK_INTERN void\nnk__lit(unsigned char *data, unsigned int length)\n{\n    NK_ASSERT (nk__dout + length <= nk__barrier);\n    if (nk__dout + length > nk__barrier) { nk__dout += length; return; }\n    if (data < nk__barrier2) { nk__dout = nk__barrier+1; return; }\n    NK_MEMCPY(nk__dout, data, length);\n    nk__dout += length;\n}\nNK_INTERN unsigned char*\nnk_decompress_token(unsigned char *i)\n{\n    #define nk__in2(x)   ((i[x] << 8) + i[(x)+1])\n    #define nk__in3(x)   ((i[x] << 16) + nk__in2((x)+1))\n    #define nk__in4(x)   ((i[x] << 24) + nk__in3((x)+1))\n\n    if (*i >= 0x20) { /* use fewer if's for cases that expand small */\n        if (*i >= 0x80)       nk__match(nk__dout-i[1]-1, (unsigned int)i[0] - 0x80 + 1), i += 2;\n        else if (*i >= 0x40)  nk__match(nk__dout-(nk__in2(0) - 0x4000 + 1), (unsigned int)i[2]+1), i += 3;\n        else /* *i >= 0x20 */ nk__lit(i+1, (unsigned int)i[0] - 0x20 + 1), i += 1 + (i[0] - 0x20 + 1);\n    } else { /* more ifs for cases that expand large, since overhead is amortized */\n        if (*i >= 0x18)       nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x180000 + 1), (unsigned int)i[3]+1), i += 4;\n        else if (*i >= 0x10)  nk__match(nk__dout-(unsigned int)(nk__in3(0) - 0x100000 + 1), (unsigned int)nk__in2(3)+1), i += 5;\n        else if (*i >= 0x08)  nk__lit(i+2, (unsigned int)nk__in2(0) - 0x0800 + 1), i += 2 + (nk__in2(0) - 0x0800 + 1);\n        else if (*i == 0x07)  nk__lit(i+3, (unsigned int)nk__in2(1) + 1), i += 3 + (nk__in2(1) + 1);\n        else if (*i == 0x06)  nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), i[4]+1u), i += 5;\n        else if (*i == 0x04)  nk__match(nk__dout-(unsigned int)(nk__in3(1)+1), (unsigned int)nk__in2(4)+1u), i += 6;\n    }\n    return i;\n}\nNK_INTERN unsigned int\nnk_adler32(unsigned int adler32, unsigned char *buffer, unsigned int buflen)\n{\n    const unsigned long ADLER_MOD = 65521;\n    unsigned long s1 = adler32 & 0xffff, s2 = adler32 >> 16;\n    unsigned long blocklen, i;\n\n    blocklen = buflen % 5552;\n    while (buflen) {\n        for (i=0; i + 7 < blocklen; i += 8) {\n            s1 += buffer[0]; s2 += s1;\n            s1 += buffer[1]; s2 += s1;\n            s1 += buffer[2]; s2 += s1;\n            s1 += buffer[3]; s2 += s1;\n            s1 += buffer[4]; s2 += s1;\n            s1 += buffer[5]; s2 += s1;\n            s1 += buffer[6]; s2 += s1;\n            s1 += buffer[7]; s2 += s1;\n            buffer += 8;\n        }\n        for (; i < blocklen; ++i) {\n            s1 += *buffer++; s2 += s1;\n        }\n\n        s1 %= ADLER_MOD; s2 %= ADLER_MOD;\n        buflen -= (unsigned int)blocklen;\n        blocklen = 5552;\n    }\n    return (unsigned int)(s2 << 16) + (unsigned int)s1;\n}\nNK_INTERN unsigned int\nnk_decompress(unsigned char *output, unsigned char *i, unsigned int length)\n{\n    unsigned int olen;\n    if (nk__in4(0) != 0x57bC0000) return 0;\n    if (nk__in4(4) != 0)          return 0; /* error! stream is > 4GB */\n    olen = nk_decompress_length(i);\n    nk__barrier2 = i;\n    nk__barrier3 = i+length;\n    nk__barrier = output + olen;\n    nk__barrier4 = output;\n    i += 16;\n\n    nk__dout = output;\n    for (;;) {\n        unsigned char *old_i = i;\n        i = nk_decompress_token(i);\n        if (i == old_i) {\n            if (*i == 0x05 && i[1] == 0xfa) {\n                NK_ASSERT(nk__dout == output + olen);\n                if (nk__dout != output + olen) return 0;\n                if (nk_adler32(1, output, olen) != (unsigned int) nk__in4(2))\n                    return 0;\n                return olen;\n            } else {\n                NK_ASSERT(0); /* NOTREACHED */\n                return 0;\n            }\n        }\n        NK_ASSERT(nk__dout <= output + olen);\n        if (nk__dout > output + olen)\n            return 0;\n    }\n}\nNK_INTERN unsigned int\nnk_decode_85_byte(char c)\n{\n    return (unsigned int)((c >= '\\\\') ? c-36 : c-35);\n}\nNK_INTERN void\nnk_decode_85(unsigned char* dst, const unsigned char* src)\n{\n    while (*src)\n    {\n        unsigned int tmp =\n            nk_decode_85_byte((char)src[0]) +\n            85 * (nk_decode_85_byte((char)src[1]) +\n            85 * (nk_decode_85_byte((char)src[2]) +\n            85 * (nk_decode_85_byte((char)src[3]) +\n            85 * nk_decode_85_byte((char)src[4]))));\n\n        /* we can't assume little-endianess. */\n        dst[0] = (unsigned char)((tmp >> 0) & 0xFF);\n        dst[1] = (unsigned char)((tmp >> 8) & 0xFF);\n        dst[2] = (unsigned char)((tmp >> 16) & 0xFF);\n        dst[3] = (unsigned char)((tmp >> 24) & 0xFF);\n\n        src += 5;\n        dst += 4;\n    }\n}\n\n/* -------------------------------------------------------------\n *\n *                          FONT ATLAS\n *\n * --------------------------------------------------------------*/\nNK_API struct nk_font_config\nnk_font_config(float pixel_height)\n{\n    struct nk_font_config cfg;\n    nk_zero_struct(cfg);\n    cfg.ttf_blob = 0;\n    cfg.ttf_size = 0;\n    cfg.ttf_data_owned_by_atlas = 0;\n    cfg.size = pixel_height;\n    cfg.oversample_h = 3;\n    cfg.oversample_v = 1;\n    cfg.pixel_snap = 0;\n    cfg.coord_type = NK_COORD_UV;\n    cfg.spacing = nk_vec2(0,0);\n    cfg.range = nk_font_default_glyph_ranges();\n    cfg.merge_mode = 0;\n    cfg.fallback_glyph = '?';\n    cfg.font = 0;\n    cfg.n = 0;\n    return cfg;\n}\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void\nnk_font_atlas_init_default(struct nk_font_atlas *atlas)\n{\n    NK_ASSERT(atlas);\n    if (!atlas) return;\n    nk_zero_struct(*atlas);\n    atlas->temporary.userdata.ptr = 0;\n    atlas->temporary.alloc = nk_malloc;\n    atlas->temporary.free = nk_mfree;\n    atlas->permanent.userdata.ptr = 0;\n    atlas->permanent.alloc = nk_malloc;\n    atlas->permanent.free = nk_mfree;\n}\n#endif\nNK_API void\nnk_font_atlas_init(struct nk_font_atlas *atlas, const struct nk_allocator *alloc)\n{\n    NK_ASSERT(atlas);\n    NK_ASSERT(alloc);\n    if (!atlas || !alloc) return;\n    nk_zero_struct(*atlas);\n    atlas->permanent = *alloc;\n    atlas->temporary = *alloc;\n}\nNK_API void\nnk_font_atlas_init_custom(struct nk_font_atlas *atlas,\n    const struct nk_allocator *permanent, const struct nk_allocator *temporary)\n{\n    NK_ASSERT(atlas);\n    NK_ASSERT(permanent);\n    NK_ASSERT(temporary);\n    if (!atlas || !permanent || !temporary) return;\n    nk_zero_struct(*atlas);\n    atlas->permanent = *permanent;\n    atlas->temporary = *temporary;\n}\nNK_API void\nnk_font_atlas_begin(struct nk_font_atlas *atlas)\n{\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc && atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc && atlas->permanent.free);\n    if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free ||\n        !atlas->temporary.alloc || !atlas->temporary.free) return;\n    if (atlas->glyphs) {\n        atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);\n        atlas->glyphs = 0;\n    }\n    if (atlas->pixel) {\n        atlas->permanent.free(atlas->permanent.userdata, atlas->pixel);\n        atlas->pixel = 0;\n    }\n}\nNK_API struct nk_font*\nnk_font_atlas_add(struct nk_font_atlas *atlas, const struct nk_font_config *config)\n{\n    struct nk_font *font = 0;\n    struct nk_font_config *cfg;\n\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n\n    NK_ASSERT(config);\n    NK_ASSERT(config->ttf_blob);\n    NK_ASSERT(config->ttf_size);\n    NK_ASSERT(config->size > 0.0f);\n\n    if (!atlas || !config || !config->ttf_blob || !config->ttf_size || config->size <= 0.0f||\n        !atlas->permanent.alloc || !atlas->permanent.free ||\n        !atlas->temporary.alloc || !atlas->temporary.free)\n        return 0;\n\n    /* allocate font config  */\n    cfg = (struct nk_font_config*)\n        atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font_config));\n    NK_MEMCPY(cfg, config, sizeof(*config));\n    cfg->n = cfg;\n    cfg->p = cfg;\n\n    if (!config->merge_mode) {\n        /* insert font config into list */\n        if (!atlas->config) {\n            atlas->config = cfg;\n            cfg->next = 0;\n        } else {\n            struct nk_font_config *i = atlas->config;\n            while (i->next) i = i->next;\n            i->next = cfg;\n            cfg->next = 0;\n        }\n        /* allocate new font */\n        font = (struct nk_font*)\n            atlas->permanent.alloc(atlas->permanent.userdata,0, sizeof(struct nk_font));\n        NK_ASSERT(font);\n        nk_zero(font, sizeof(*font));\n        if (!font) return 0;\n        font->config = cfg;\n\n        /* insert font into list */\n        if (!atlas->fonts) {\n            atlas->fonts = font;\n            font->next = 0;\n        } else {\n            struct nk_font *i = atlas->fonts;\n            while (i->next) i = i->next;\n            i->next = font;\n            font->next = 0;\n        }\n        cfg->font = &font->info;\n    } else {\n        /* extend previously added font */\n        struct nk_font *f = 0;\n        struct nk_font_config *c = 0;\n        NK_ASSERT(atlas->font_num);\n        f = atlas->fonts;\n        c = f->config;\n        cfg->font = &f->info;\n\n        cfg->n = c;\n        cfg->p = c->p;\n        c->p->n = cfg;\n        c->p = cfg;\n    }\n    /* create own copy of .TTF font blob */\n    if (!config->ttf_data_owned_by_atlas) {\n        cfg->ttf_blob = atlas->permanent.alloc(atlas->permanent.userdata,0, cfg->ttf_size);\n        NK_ASSERT(cfg->ttf_blob);\n        if (!cfg->ttf_blob) {\n            atlas->font_num++;\n            return 0;\n        }\n        NK_MEMCPY(cfg->ttf_blob, config->ttf_blob, cfg->ttf_size);\n        cfg->ttf_data_owned_by_atlas = 1;\n    }\n    atlas->font_num++;\n    return font;\n}\nNK_API struct nk_font*\nnk_font_atlas_add_from_memory(struct nk_font_atlas *atlas, void *memory,\n    nk_size size, float height, const struct nk_font_config *config)\n{\n    struct nk_font_config cfg;\n    NK_ASSERT(memory);\n    NK_ASSERT(size);\n\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n    if (!atlas || !atlas->temporary.alloc || !atlas->temporary.free || !memory || !size ||\n        !atlas->permanent.alloc || !atlas->permanent.free)\n        return 0;\n\n    cfg = (config) ? *config: nk_font_config(height);\n    cfg.ttf_blob = memory;\n    cfg.ttf_size = size;\n    cfg.size = height;\n    cfg.ttf_data_owned_by_atlas = 0;\n    return nk_font_atlas_add(atlas, &cfg);\n}\n#ifdef NK_INCLUDE_STANDARD_IO\nNK_API struct nk_font*\nnk_font_atlas_add_from_file(struct nk_font_atlas *atlas, const char *file_path,\n    float height, const struct nk_font_config *config)\n{\n    nk_size size;\n    char *memory;\n    struct nk_font_config cfg;\n\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n\n    if (!atlas || !file_path) return 0;\n    memory = nk_file_load(file_path, &size, &atlas->permanent);\n    if (!memory) return 0;\n\n    cfg = (config) ? *config: nk_font_config(height);\n    cfg.ttf_blob = memory;\n    cfg.ttf_size = size;\n    cfg.size = height;\n    cfg.ttf_data_owned_by_atlas = 1;\n    return nk_font_atlas_add(atlas, &cfg);\n}\n#endif\nNK_API struct nk_font*\nnk_font_atlas_add_compressed(struct nk_font_atlas *atlas,\n    void *compressed_data, nk_size compressed_size, float height,\n    const struct nk_font_config *config)\n{\n    unsigned int decompressed_size;\n    void *decompressed_data;\n    struct nk_font_config cfg;\n\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n\n    NK_ASSERT(compressed_data);\n    NK_ASSERT(compressed_size);\n    if (!atlas || !compressed_data || !atlas->temporary.alloc || !atlas->temporary.free ||\n        !atlas->permanent.alloc || !atlas->permanent.free)\n        return 0;\n\n    decompressed_size = nk_decompress_length((unsigned char*)compressed_data);\n    decompressed_data = atlas->permanent.alloc(atlas->permanent.userdata,0,decompressed_size);\n    NK_ASSERT(decompressed_data);\n    if (!decompressed_data) return 0;\n    nk_decompress((unsigned char*)decompressed_data, (unsigned char*)compressed_data,\n        (unsigned int)compressed_size);\n\n    cfg = (config) ? *config: nk_font_config(height);\n    cfg.ttf_blob = decompressed_data;\n    cfg.ttf_size = decompressed_size;\n    cfg.size = height;\n    cfg.ttf_data_owned_by_atlas = 1;\n    return nk_font_atlas_add(atlas, &cfg);\n}\nNK_API struct nk_font*\nnk_font_atlas_add_compressed_base85(struct nk_font_atlas *atlas,\n    const char *data_base85, float height, const struct nk_font_config *config)\n{\n    int compressed_size;\n    void *compressed_data;\n    struct nk_font *font;\n\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n\n    NK_ASSERT(data_base85);\n    if (!atlas || !data_base85 || !atlas->temporary.alloc || !atlas->temporary.free ||\n        !atlas->permanent.alloc || !atlas->permanent.free)\n        return 0;\n\n    compressed_size = (((int)nk_strlen(data_base85) + 4) / 5) * 4;\n    compressed_data = atlas->temporary.alloc(atlas->temporary.userdata,0, (nk_size)compressed_size);\n    NK_ASSERT(compressed_data);\n    if (!compressed_data) return 0;\n    nk_decode_85((unsigned char*)compressed_data, (const unsigned char*)data_base85);\n    font = nk_font_atlas_add_compressed(atlas, compressed_data,\n                    (nk_size)compressed_size, height, config);\n    atlas->temporary.free(atlas->temporary.userdata, compressed_data);\n    return font;\n}\n\n#ifdef NK_INCLUDE_DEFAULT_FONT\nNK_API struct nk_font*\nnk_font_atlas_add_default(struct nk_font_atlas *atlas,\n    float pixel_height, const struct nk_font_config *config)\n{\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n    return nk_font_atlas_add_compressed_base85(atlas,\n        nk_proggy_clean_ttf_compressed_data_base85, pixel_height, config);\n}\n#endif\nNK_API const void*\nnk_font_atlas_bake(struct nk_font_atlas *atlas, int *width, int *height,\n    enum nk_font_atlas_format fmt)\n{\n    int i = 0;\n    void *tmp = 0;\n    nk_size tmp_size, img_size;\n    struct nk_font *font_iter;\n    struct nk_font_baker *baker;\n\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n\n    NK_ASSERT(width);\n    NK_ASSERT(height);\n    if (!atlas || !width || !height ||\n        !atlas->temporary.alloc || !atlas->temporary.free ||\n        !atlas->permanent.alloc || !atlas->permanent.free)\n        return 0;\n\n#ifdef NK_INCLUDE_DEFAULT_FONT\n    /* no font added so just use default font */\n    if (!atlas->font_num)\n        atlas->default_font = nk_font_atlas_add_default(atlas, 13.0f, 0);\n#endif\n    NK_ASSERT(atlas->font_num);\n    if (!atlas->font_num) return 0;\n\n    /* allocate temporary baker memory required for the baking process */\n    nk_font_baker_memory(&tmp_size, &atlas->glyph_count, atlas->config, atlas->font_num);\n    tmp = atlas->temporary.alloc(atlas->temporary.userdata,0, tmp_size);\n    NK_ASSERT(tmp);\n    if (!tmp) goto failed;\n    NK_MEMSET(tmp,0,tmp_size);\n\n    /* allocate glyph memory for all fonts */\n    baker = nk_font_baker(tmp, atlas->glyph_count, atlas->font_num, &atlas->temporary);\n    atlas->glyphs = (struct nk_font_glyph*)atlas->permanent.alloc(\n        atlas->permanent.userdata,0, sizeof(struct nk_font_glyph)*(nk_size)atlas->glyph_count);\n    NK_ASSERT(atlas->glyphs);\n    if (!atlas->glyphs)\n        goto failed;\n\n    /* pack all glyphs into a tight fit space */\n    atlas->custom.w = (NK_CURSOR_DATA_W*2)+1;\n    atlas->custom.h = NK_CURSOR_DATA_H + 1;\n    if (!nk_font_bake_pack(baker, &img_size, width, height, &atlas->custom,\n        atlas->config, atlas->font_num, &atlas->temporary))\n        goto failed;\n\n    /* allocate memory for the baked image font atlas */\n    atlas->pixel = atlas->temporary.alloc(atlas->temporary.userdata,0, img_size);\n    NK_ASSERT(atlas->pixel);\n    if (!atlas->pixel)\n        goto failed;\n\n    /* bake glyphs and custom white pixel into image */\n    nk_font_bake(baker, atlas->pixel, *width, *height,\n        atlas->glyphs, atlas->glyph_count, atlas->config, atlas->font_num);\n    nk_font_bake_custom_data(atlas->pixel, *width, *height, atlas->custom,\n            nk_custom_cursor_data, NK_CURSOR_DATA_W, NK_CURSOR_DATA_H, '.', 'X');\n\n    if (fmt == NK_FONT_ATLAS_RGBA32) {\n        /* convert alpha8 image into rgba32 image */\n        void *img_rgba = atlas->temporary.alloc(atlas->temporary.userdata,0,\n                            (nk_size)(*width * *height * 4));\n        NK_ASSERT(img_rgba);\n        if (!img_rgba) goto failed;\n        nk_font_bake_convert(img_rgba, *width, *height, atlas->pixel);\n        atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);\n        atlas->pixel = img_rgba;\n    }\n    atlas->tex_width = *width;\n    atlas->tex_height = *height;\n\n    /* initialize each font */\n    for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) {\n        struct nk_font *font = font_iter;\n        struct nk_font_config *config = font->config;\n        nk_font_init(font, config->size, config->fallback_glyph, atlas->glyphs,\n            config->font, nk_handle_ptr(0));\n    }\n\n    /* initialize each cursor */\n    {NK_STORAGE const struct nk_vec2 nk_cursor_data[NK_CURSOR_COUNT][3] = {\n        /* Pos      Size        Offset */\n        {{ 0, 3},   {12,19},    { 0, 0}},\n        {{13, 0},   { 7,16},    { 4, 8}},\n        {{31, 0},   {23,23},    {11,11}},\n        {{21, 0},   { 9, 23},   { 5,11}},\n        {{55,18},   {23, 9},    {11, 5}},\n        {{73, 0},   {17,17},    { 9, 9}},\n        {{55, 0},   {17,17},    { 9, 9}}\n    };\n    for (i = 0; i < NK_CURSOR_COUNT; ++i) {\n        struct nk_cursor *cursor = &atlas->cursors[i];\n        cursor->img.w = (unsigned short)*width;\n        cursor->img.h = (unsigned short)*height;\n        cursor->img.region[0] = (unsigned short)(atlas->custom.x + nk_cursor_data[i][0].x);\n        cursor->img.region[1] = (unsigned short)(atlas->custom.y + nk_cursor_data[i][0].y);\n        cursor->img.region[2] = (unsigned short)nk_cursor_data[i][1].x;\n        cursor->img.region[3] = (unsigned short)nk_cursor_data[i][1].y;\n        cursor->size = nk_cursor_data[i][1];\n        cursor->offset = nk_cursor_data[i][2];\n    }}\n    /* free temporary memory */\n    atlas->temporary.free(atlas->temporary.userdata, tmp);\n    return atlas->pixel;\n\nfailed:\n    /* error so cleanup all memory */\n    if (tmp) atlas->temporary.free(atlas->temporary.userdata, tmp);\n    if (atlas->glyphs) {\n        atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);\n        atlas->glyphs = 0;\n    }\n    if (atlas->pixel) {\n        atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);\n        atlas->pixel = 0;\n    }\n    return 0;\n}\nNK_API void\nnk_font_atlas_end(struct nk_font_atlas *atlas, nk_handle texture,\n    struct nk_draw_null_texture *tex_null)\n{\n    int i = 0;\n    struct nk_font *font_iter;\n    NK_ASSERT(atlas);\n    if (!atlas) {\n        if (!tex_null) return;\n        tex_null->texture = texture;\n        tex_null->uv = nk_vec2(0.5f,0.5f);\n    }\n    if (tex_null) {\n        tex_null->texture = texture;\n        tex_null->uv.x = (atlas->custom.x + 0.5f)/(float)atlas->tex_width;\n        tex_null->uv.y = (atlas->custom.y + 0.5f)/(float)atlas->tex_height;\n    }\n    for (font_iter = atlas->fonts; font_iter; font_iter = font_iter->next) {\n        font_iter->texture = texture;\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\n        font_iter->handle.texture = texture;\n#endif\n    }\n    for (i = 0; i < NK_CURSOR_COUNT; ++i)\n        atlas->cursors[i].img.handle = texture;\n\n    atlas->temporary.free(atlas->temporary.userdata, atlas->pixel);\n    atlas->pixel = 0;\n    atlas->tex_width = 0;\n    atlas->tex_height = 0;\n    atlas->custom.x = 0;\n    atlas->custom.y = 0;\n    atlas->custom.w = 0;\n    atlas->custom.h = 0;\n}\nNK_API void\nnk_font_atlas_cleanup(struct nk_font_atlas *atlas)\n{\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n    if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return;\n    if (atlas->config) {\n        struct nk_font_config *iter;\n        for (iter = atlas->config; iter; iter = iter->next) {\n            struct nk_font_config *i;\n            for (i = iter->n; i != iter; i = i->n) {\n                atlas->permanent.free(atlas->permanent.userdata, i->ttf_blob);\n                i->ttf_blob = 0;\n            }\n            atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob);\n            iter->ttf_blob = 0;\n        }\n    }\n}\nNK_API void\nnk_font_atlas_clear(struct nk_font_atlas *atlas)\n{\n    NK_ASSERT(atlas);\n    NK_ASSERT(atlas->temporary.alloc);\n    NK_ASSERT(atlas->temporary.free);\n    NK_ASSERT(atlas->permanent.alloc);\n    NK_ASSERT(atlas->permanent.free);\n    if (!atlas || !atlas->permanent.alloc || !atlas->permanent.free) return;\n\n    if (atlas->config) {\n        struct nk_font_config *iter, *next;\n        for (iter = atlas->config; iter; iter = next) {\n            struct nk_font_config *i, *n;\n            for (i = iter->n; i != iter; i = n) {\n                n = i->n;\n                if (i->ttf_blob)\n                    atlas->permanent.free(atlas->permanent.userdata, i->ttf_blob);\n                atlas->permanent.free(atlas->permanent.userdata, i);\n            }\n            next = iter->next;\n            if (i->ttf_blob)\n                atlas->permanent.free(atlas->permanent.userdata, iter->ttf_blob);\n            atlas->permanent.free(atlas->permanent.userdata, iter);\n        }\n        atlas->config = 0;\n    }\n    if (atlas->fonts) {\n        struct nk_font *iter, *next;\n        for (iter = atlas->fonts; iter; iter = next) {\n            next = iter->next;\n            atlas->permanent.free(atlas->permanent.userdata, iter);\n        }\n        atlas->fonts = 0;\n    }\n    if (atlas->glyphs)\n        atlas->permanent.free(atlas->permanent.userdata, atlas->glyphs);\n    nk_zero_struct(*atlas);\n}\n#endif\n"
  },
  {
    "path": "src/nuklear_group.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                          GROUP\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_group_scrolled_offset_begin(struct nk_context *ctx,\n    nk_uint *x_offset, nk_uint *y_offset, const char *title, nk_flags flags)\n{\n    struct nk_rect bounds;\n    struct nk_window panel;\n    struct nk_window *win;\n\n    win = ctx->current;\n    nk_panel_alloc_space(&bounds, ctx);\n    {const struct nk_rect *c = &win->layout->clip;\n    if (!NK_INTERSECT(c->x, c->y, c->w, c->h, bounds.x, bounds.y, bounds.w, bounds.h) &&\n        !(flags & NK_WINDOW_MOVABLE)) {\n        return 0;\n    }}\n    if (win->flags & NK_WINDOW_ROM)\n        flags |= NK_WINDOW_ROM;\n\n    /* initialize a fake window to create the panel from */\n    nk_zero(&panel, sizeof(panel));\n    panel.bounds = bounds;\n    panel.flags = flags;\n    panel.scrollbar.x = *x_offset;\n    panel.scrollbar.y = *y_offset;\n    panel.buffer = win->buffer;\n    panel.layout = (struct nk_panel*)nk_create_panel(ctx);\n    ctx->current = &panel;\n    nk_panel_begin(ctx, (flags & NK_WINDOW_TITLE) ? title: 0, NK_PANEL_GROUP);\n\n    win->buffer = panel.buffer;\n    win->buffer.clip = panel.layout->clip;\n    panel.layout->offset_x = x_offset;\n    panel.layout->offset_y = y_offset;\n    panel.layout->parent = win->layout;\n    win->layout = panel.layout;\n\n    ctx->current = win;\n    if ((panel.layout->flags & NK_WINDOW_CLOSED) ||\n        (panel.layout->flags & NK_WINDOW_MINIMIZED))\n    {\n        nk_flags f = panel.layout->flags;\n        nk_group_scrolled_end(ctx);\n        if (f & NK_WINDOW_CLOSED)\n            return NK_WINDOW_CLOSED;\n        if (f & NK_WINDOW_MINIMIZED)\n            return NK_WINDOW_MINIMIZED;\n    }\n    return 1;\n}\nNK_API void\nnk_group_scrolled_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *parent;\n    struct nk_panel *g;\n\n    struct nk_rect clip;\n    struct nk_window pan;\n    struct nk_vec2 panel_padding;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return;\n\n    /* make sure nk_group_begin was called correctly */\n    NK_ASSERT(ctx->current);\n    win = ctx->current;\n    NK_ASSERT(win->layout);\n    g = win->layout;\n    NK_ASSERT(g->parent);\n    parent = g->parent;\n\n    /* dummy window */\n    nk_zero_struct(pan);\n    panel_padding = nk_panel_get_padding(&ctx->style, NK_PANEL_GROUP);\n    pan.bounds.y = g->bounds.y - (g->header_height + g->menu.h);\n    pan.bounds.x = g->bounds.x - panel_padding.x;\n    pan.bounds.w = g->bounds.w + 2 * panel_padding.x;\n    pan.bounds.h = g->bounds.h + g->header_height + g->menu.h;\n    if (g->flags & NK_WINDOW_BORDER) {\n        pan.bounds.x -= g->border;\n        pan.bounds.y -= g->border;\n        pan.bounds.w += 2*g->border;\n        pan.bounds.h += 2*g->border;\n    }\n    if (!(g->flags & NK_WINDOW_NO_SCROLLBAR)) {\n        pan.bounds.w += ctx->style.window.scrollbar_size.x;\n        pan.bounds.h += ctx->style.window.scrollbar_size.y;\n    }\n    pan.scrollbar.x = *g->offset_x;\n    pan.scrollbar.y = *g->offset_y;\n    pan.flags = g->flags;\n    pan.buffer = win->buffer;\n    pan.layout = g;\n    pan.parent = win;\n    ctx->current = &pan;\n\n    /* make sure group has correct clipping rectangle */\n    nk_unify(&clip, &parent->clip, pan.bounds.x, pan.bounds.y,\n        pan.bounds.x + pan.bounds.w, pan.bounds.y + pan.bounds.h + panel_padding.x);\n    nk_push_scissor(&pan.buffer, clip);\n    nk_end(ctx);\n\n    win->buffer = pan.buffer;\n    nk_push_scissor(&win->buffer, parent->clip);\n    ctx->current = win;\n    win->layout = parent;\n    g->bounds = pan.bounds;\n    return;\n}\nNK_API nk_bool\nnk_group_scrolled_begin(struct nk_context *ctx,\n    struct nk_scroll *scroll, const char *title, nk_flags flags)\n{\n    return nk_group_scrolled_offset_begin(ctx, &scroll->x, &scroll->y, title, flags);\n}\nNK_API nk_bool\nnk_group_begin_titled(struct nk_context *ctx, const char *id,\n    const char *title, nk_flags flags)\n{\n    int id_len;\n    nk_hash id_hash;\n    struct nk_window *win;\n    nk_uint *x_offset;\n    nk_uint *y_offset;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(id);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !id)\n        return 0;\n\n    /* find persistent group scrollbar value */\n    win = ctx->current;\n    id_len = (int)nk_strlen(id);\n    id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP);\n    x_offset = nk_find_value(win, id_hash);\n    if (!x_offset) {\n        x_offset = nk_add_value(ctx, win, id_hash, 0);\n        y_offset = nk_add_value(ctx, win, id_hash+1, 0);\n\n        NK_ASSERT(x_offset);\n        NK_ASSERT(y_offset);\n        if (!x_offset || !y_offset) return 0;\n        *x_offset = *y_offset = 0;\n    } else if (!(y_offset = nk_find_value(win, id_hash+1))) {\n        y_offset = nk_add_value(ctx, win, id_hash+1, 0);\n        NK_ASSERT(y_offset);\n        if (!y_offset) return 0;\n        *x_offset = *y_offset = 0; /* I think this covers the degenerate case */\n    }\n\n    return nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);\n}\nNK_API nk_bool\nnk_group_begin(struct nk_context *ctx, const char *title, nk_flags flags)\n{\n    return nk_group_begin_titled(ctx, title, title, flags);\n}\nNK_API void\nnk_group_end(struct nk_context *ctx)\n{\n    nk_group_scrolled_end(ctx);\n}\nNK_API void\nnk_group_get_scroll(struct nk_context *ctx, const char *id, nk_uint *x_offset, nk_uint *y_offset)\n{\n    int id_len;\n    nk_hash id_hash;\n    struct nk_window *win;\n    nk_uint *x_offset_ptr;\n    nk_uint *y_offset_ptr;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(id);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !id)\n        return;\n\n    /* find persistent group scrollbar value */\n    win = ctx->current;\n    id_len = (int)nk_strlen(id);\n    id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP);\n    x_offset_ptr = nk_find_value(win, id_hash);\n    if (!x_offset_ptr) {\n        x_offset_ptr = nk_add_value(ctx, win, id_hash, 0);\n        y_offset_ptr = nk_add_value(ctx, win, id_hash+1, 0);\n\n        NK_ASSERT(x_offset_ptr);\n        NK_ASSERT(y_offset_ptr);\n        if (!x_offset_ptr || !y_offset_ptr) return;\n        *x_offset_ptr = *y_offset_ptr = 0;\n    } else if (!(y_offset_ptr = nk_find_value(win, id_hash+1))) {\n        y_offset_ptr = nk_add_value(ctx, win, id_hash+1, 0);\n        NK_ASSERT(y_offset_ptr);\n        if (!y_offset_ptr) return;\n        *x_offset_ptr = *y_offset_ptr = 0;\n    }\n    if (x_offset)\n      *x_offset = *x_offset_ptr;\n    if (y_offset)\n      *y_offset = *y_offset_ptr;\n}\nNK_API void\nnk_group_set_scroll(struct nk_context *ctx, const char *id, nk_uint x_offset, nk_uint y_offset)\n{\n    int id_len;\n    nk_hash id_hash;\n    struct nk_window *win;\n    nk_uint *x_offset_ptr;\n    nk_uint *y_offset_ptr;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(id);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !id)\n        return;\n\n    /* find persistent group scrollbar value */\n    win = ctx->current;\n    id_len = (int)nk_strlen(id);\n    id_hash = nk_murmur_hash(id, (int)id_len, NK_PANEL_GROUP);\n    x_offset_ptr = nk_find_value(win, id_hash);\n    if (!x_offset_ptr) {\n        x_offset_ptr = nk_add_value(ctx, win, id_hash, 0);\n        y_offset_ptr = nk_add_value(ctx, win, id_hash+1, 0);\n\n        NK_ASSERT(x_offset_ptr);\n        NK_ASSERT(y_offset_ptr);\n        if (!x_offset_ptr || !y_offset_ptr) return;\n        *x_offset_ptr = *y_offset_ptr = 0;\n    } else if (!(y_offset_ptr = nk_find_value(win, id_hash+1))) {\n        NK_ASSERT(y_offset_ptr);\n        if (!y_offset_ptr) return;\n        *x_offset_ptr = *y_offset_ptr = 0;\n    }\n    *x_offset_ptr = x_offset;\n    *y_offset_ptr = y_offset;\n}\n"
  },
  {
    "path": "src/nuklear_image.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                          IMAGE\n *\n * ===============================================================*/\nNK_API nk_handle\nnk_handle_ptr(void *ptr)\n{\n    nk_handle handle = {0};\n    handle.ptr = ptr;\n    return handle;\n}\nNK_API nk_handle\nnk_handle_id(int id)\n{\n    nk_handle handle;\n    nk_zero_struct(handle);\n    handle.id = id;\n    return handle;\n}\nNK_API struct nk_image\nnk_subimage_ptr(void *ptr, nk_ushort w, nk_ushort h, struct nk_rect r)\n{\n    struct nk_image s;\n    nk_zero(&s, sizeof(s));\n    s.handle.ptr = ptr;\n    s.w = w; s.h = h;\n    s.region[0] = (nk_ushort)r.x;\n    s.region[1] = (nk_ushort)r.y;\n    s.region[2] = (nk_ushort)r.w;\n    s.region[3] = (nk_ushort)r.h;\n    return s;\n}\nNK_API struct nk_image\nnk_subimage_id(int id, nk_ushort w, nk_ushort h, struct nk_rect r)\n{\n    struct nk_image s;\n    nk_zero(&s, sizeof(s));\n    s.handle.id = id;\n    s.w = w; s.h = h;\n    s.region[0] = (nk_ushort)r.x;\n    s.region[1] = (nk_ushort)r.y;\n    s.region[2] = (nk_ushort)r.w;\n    s.region[3] = (nk_ushort)r.h;\n    return s;\n}\nNK_API struct nk_image\nnk_subimage_handle(nk_handle handle, nk_ushort w, nk_ushort h, struct nk_rect r)\n{\n    struct nk_image s;\n    nk_zero(&s, sizeof(s));\n    s.handle = handle;\n    s.w = w; s.h = h;\n    s.region[0] = (nk_ushort)r.x;\n    s.region[1] = (nk_ushort)r.y;\n    s.region[2] = (nk_ushort)r.w;\n    s.region[3] = (nk_ushort)r.h;\n    return s;\n}\nNK_API struct nk_image\nnk_image_handle(nk_handle handle)\n{\n    struct nk_image s;\n    nk_zero(&s, sizeof(s));\n    s.handle = handle;\n    s.w = 0; s.h = 0;\n    s.region[0] = 0;\n    s.region[1] = 0;\n    s.region[2] = 0;\n    s.region[3] = 0;\n    return s;\n}\nNK_API struct nk_image\nnk_image_ptr(void *ptr)\n{\n    struct nk_image s;\n    nk_zero(&s, sizeof(s));\n    NK_ASSERT(ptr);\n    s.handle.ptr = ptr;\n    s.w = 0; s.h = 0;\n    s.region[0] = 0;\n    s.region[1] = 0;\n    s.region[2] = 0;\n    s.region[3] = 0;\n    return s;\n}\nNK_API struct nk_image\nnk_image_id(int id)\n{\n    struct nk_image s;\n    nk_zero(&s, sizeof(s));\n    s.handle.id = id;\n    s.w = 0; s.h = 0;\n    s.region[0] = 0;\n    s.region[1] = 0;\n    s.region[2] = 0;\n    s.region[3] = 0;\n    return s;\n}\nNK_API nk_bool\nnk_image_is_subimage(const struct nk_image* img)\n{\n    NK_ASSERT(img);\n    return !(img->w == 0 && img->h == 0);\n}\nNK_API void\nnk_image(struct nk_context *ctx, struct nk_image img)\n{\n    struct nk_window *win;\n    struct nk_rect bounds;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) return;\n\n    win = ctx->current;\n    if (!nk_widget(&bounds, ctx)) return;\n    nk_draw_image(&win->buffer, bounds, &img, nk_white);\n}\nNK_API void\nnk_image_color(struct nk_context *ctx, struct nk_image img, struct nk_color col)\n{\n    struct nk_window *win;\n    struct nk_rect bounds;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) return;\n\n    win = ctx->current;\n    if (!nk_widget(&bounds, ctx)) return;\n    nk_draw_image(&win->buffer, bounds, &img, col);\n}\n\n"
  },
  {
    "path": "src/nuklear_input.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                          INPUT\n *\n * ===============================================================*/\nNK_API void\nnk_input_begin(struct nk_context *ctx)\n{\n    int i;\n    struct nk_input *in;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    in = &ctx->input;\n    for (i = 0; i < NK_BUTTON_MAX; ++i)\n        in->mouse.buttons[i].clicked = 0;\n\n    in->keyboard.text_len = 0;\n    in->mouse.scroll_delta = nk_vec2(0,0);\n    in->mouse.prev.x = in->mouse.pos.x;\n    in->mouse.prev.y = in->mouse.pos.y;\n    in->mouse.delta.x = 0;\n    in->mouse.delta.y = 0;\n    for (i = 0; i < NK_KEY_MAX; i++)\n        in->keyboard.keys[i].clicked = 0;\n}\nNK_API void\nnk_input_end(struct nk_context *ctx)\n{\n    struct nk_input *in;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    in = &ctx->input;\n    if (in->mouse.grab)\n        in->mouse.grab = 0;\n    if (in->mouse.ungrab) {\n        in->mouse.grabbed = 0;\n        in->mouse.ungrab = 0;\n        in->mouse.grab = 0;\n    }\n}\nNK_API void\nnk_input_motion(struct nk_context *ctx, int x, int y)\n{\n    struct nk_input *in;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    in = &ctx->input;\n    in->mouse.pos.x = (float)x;\n    in->mouse.pos.y = (float)y;\n    in->mouse.delta.x = in->mouse.pos.x - in->mouse.prev.x;\n    in->mouse.delta.y = in->mouse.pos.y - in->mouse.prev.y;\n}\nNK_API void\nnk_input_key(struct nk_context *ctx, enum nk_keys key, nk_bool down)\n{\n    struct nk_input *in;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    in = &ctx->input;\n#ifdef NK_KEYSTATE_BASED_INPUT\n    if (in->keyboard.keys[key].down != down)\n        in->keyboard.keys[key].clicked++;\n#else\n    in->keyboard.keys[key].clicked++;\n#endif\n    in->keyboard.keys[key].down = down;\n}\nNK_API void\nnk_input_button(struct nk_context *ctx, enum nk_buttons id, int x, int y, nk_bool down)\n{\n    struct nk_mouse_button *btn;\n    struct nk_input *in;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    in = &ctx->input;\n    if (in->mouse.buttons[id].down == down) return;\n\n    btn = &in->mouse.buttons[id];\n    btn->clicked_pos.x = (float)x;\n    btn->clicked_pos.y = (float)y;\n    btn->down = down;\n    btn->clicked++;\n\n    /* Fix Click-Drag for touch events. */\n    in->mouse.delta.x = 0;\n    in->mouse.delta.y = 0;\n#ifdef NK_BUTTON_TRIGGER_ON_RELEASE\n    if (down == 1 && id == NK_BUTTON_LEFT)\n    {\n        in->mouse.down_pos.x = btn->clicked_pos.x;\n        in->mouse.down_pos.y = btn->clicked_pos.y;\n    }\n#endif\n}\nNK_API void\nnk_input_scroll(struct nk_context *ctx, struct nk_vec2 val)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    ctx->input.mouse.scroll_delta.x += val.x;\n    ctx->input.mouse.scroll_delta.y += val.y;\n}\nNK_API void\nnk_input_glyph(struct nk_context *ctx, const nk_glyph glyph)\n{\n    int len = 0;\n    nk_rune unicode;\n    struct nk_input *in;\n\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    in = &ctx->input;\n\n    len = nk_utf_decode(glyph, &unicode, NK_UTF_SIZE);\n    if (len && ((in->keyboard.text_len + len) < NK_INPUT_MAX)) {\n        nk_utf_encode(unicode, &in->keyboard.text[in->keyboard.text_len],\n            NK_INPUT_MAX - in->keyboard.text_len);\n        in->keyboard.text_len += len;\n    }\n}\nNK_API void\nnk_input_char(struct nk_context *ctx, char c)\n{\n    nk_glyph glyph = {0};\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    glyph[0] = c;\n    nk_input_glyph(ctx, glyph);\n}\nNK_API void\nnk_input_unicode(struct nk_context *ctx, nk_rune unicode)\n{\n    nk_glyph rune;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    nk_utf_encode(unicode, rune, NK_UTF_SIZE);\n    nk_input_glyph(ctx, rune);\n}\nNK_API nk_bool\nnk_input_has_mouse_click(const struct nk_input *i, enum nk_buttons id)\n{\n    const struct nk_mouse_button *btn;\n    if (!i) return nk_false;\n    btn = &i->mouse.buttons[id];\n    return (btn->clicked && btn->down == nk_false) ? nk_true : nk_false;\n}\nNK_API nk_bool\nnk_input_has_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id,\n    struct nk_rect b)\n{\n    const struct nk_mouse_button *btn;\n    if (!i) return nk_false;\n    btn = &i->mouse.buttons[id];\n    if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h))\n        return nk_false;\n    return nk_true;\n}\nNK_API nk_bool\nnk_input_has_mouse_click_in_button_rect(const struct nk_input *i, enum nk_buttons id,\n    struct nk_rect b)\n{\n    const struct nk_mouse_button *btn;\n    if (!i) return nk_false;\n    btn = &i->mouse.buttons[id];\n#ifdef NK_BUTTON_TRIGGER_ON_RELEASE\n    if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h)\n        || !NK_INBOX(i->mouse.down_pos.x,i->mouse.down_pos.y,b.x,b.y,b.w,b.h))\n#else\n    if (!NK_INBOX(btn->clicked_pos.x,btn->clicked_pos.y,b.x,b.y,b.w,b.h))\n#endif\n        return nk_false;\n    return nk_true;\n}\nNK_API nk_bool\nnk_input_has_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,\n    struct nk_rect b, nk_bool down)\n{\n    const struct nk_mouse_button *btn;\n    if (!i) return nk_false;\n    btn = &i->mouse.buttons[id];\n    return nk_input_has_mouse_click_in_rect(i, id, b) && (btn->down == down);\n}\nNK_API nk_bool\nnk_input_is_mouse_click_in_rect(const struct nk_input *i, enum nk_buttons id,\n    struct nk_rect b)\n{\n    const struct nk_mouse_button *btn;\n    if (!i) return nk_false;\n    btn = &i->mouse.buttons[id];\n    return (nk_input_has_mouse_click_down_in_rect(i, id, b, nk_false) &&\n            btn->clicked) ? nk_true : nk_false;\n}\nNK_API nk_bool\nnk_input_is_mouse_click_down_in_rect(const struct nk_input *i, enum nk_buttons id,\n    struct nk_rect b, nk_bool down)\n{\n    const struct nk_mouse_button *btn;\n    if (!i) return nk_false;\n    btn = &i->mouse.buttons[id];\n    return (nk_input_has_mouse_click_down_in_rect(i, id, b, down) &&\n            btn->clicked) ? nk_true : nk_false;\n}\nNK_API nk_bool\nnk_input_any_mouse_click_in_rect(const struct nk_input *in, struct nk_rect b)\n{\n    int i, down = 0;\n    for (i = 0; i < NK_BUTTON_MAX; ++i)\n        down = down || nk_input_is_mouse_click_in_rect(in, (enum nk_buttons)i, b);\n    return down;\n}\nNK_API nk_bool\nnk_input_is_mouse_hovering_rect(const struct nk_input *i, struct nk_rect rect)\n{\n    if (!i) return nk_false;\n    return NK_INBOX(i->mouse.pos.x, i->mouse.pos.y, rect.x, rect.y, rect.w, rect.h);\n}\nNK_API nk_bool\nnk_input_is_mouse_prev_hovering_rect(const struct nk_input *i, struct nk_rect rect)\n{\n    if (!i) return nk_false;\n    return NK_INBOX(i->mouse.prev.x, i->mouse.prev.y, rect.x, rect.y, rect.w, rect.h);\n}\nNK_API nk_bool\nnk_input_mouse_clicked(const struct nk_input *i, enum nk_buttons id, struct nk_rect rect)\n{\n    if (!i) return nk_false;\n    if (!nk_input_is_mouse_hovering_rect(i, rect)) return nk_false;\n    return nk_input_is_mouse_click_in_rect(i, id, rect);\n}\nNK_API nk_bool\nnk_input_is_mouse_down(const struct nk_input *i, enum nk_buttons id)\n{\n    if (!i) return nk_false;\n    return i->mouse.buttons[id].down;\n}\nNK_API nk_bool\nnk_input_is_mouse_pressed(const struct nk_input *i, enum nk_buttons id)\n{\n    const struct nk_mouse_button *b;\n    if (!i) return nk_false;\n    b = &i->mouse.buttons[id];\n    if (b->down && b->clicked)\n        return nk_true;\n    return nk_false;\n}\nNK_API nk_bool\nnk_input_is_mouse_released(const struct nk_input *i, enum nk_buttons id)\n{\n    if (!i) return nk_false;\n    return (!i->mouse.buttons[id].down && i->mouse.buttons[id].clicked);\n}\nNK_API nk_bool\nnk_input_is_mouse_moved(const struct nk_input *i)\n{\n    if (!i) return nk_false;\n    return i->mouse.delta.x != 0 || i->mouse.delta.y != 0;\n}\nNK_API nk_bool\nnk_input_is_key_pressed(const struct nk_input *i, enum nk_keys key)\n{\n    const struct nk_key *k;\n    if (!i) return nk_false;\n    k = &i->keyboard.keys[key];\n    if ((k->down && k->clicked) || (!k->down && k->clicked >= 2))\n        return nk_true;\n    return nk_false;\n}\nNK_API nk_bool\nnk_input_is_key_released(const struct nk_input *i, enum nk_keys key)\n{\n    const struct nk_key *k;\n    if (!i) return nk_false;\n    k = &i->keyboard.keys[key];\n    if ((!k->down && k->clicked) || (k->down && k->clicked >= 2))\n        return nk_true;\n    return nk_false;\n}\nNK_API nk_bool\nnk_input_is_key_down(const struct nk_input *i, enum nk_keys key)\n{\n    const struct nk_key *k;\n    if (!i) return nk_false;\n    k = &i->keyboard.keys[key];\n    if (k->down) return nk_true;\n    return nk_false;\n}\n\n"
  },
  {
    "path": "src/nuklear_internal.h",
    "content": "#ifndef NK_INTERNAL_H\n#define NK_INTERNAL_H\n\n#ifndef NK_POOL_DEFAULT_CAPACITY\n#define NK_POOL_DEFAULT_CAPACITY 16\n#endif\n\n#ifndef NK_DEFAULT_COMMAND_BUFFER_SIZE\n#define NK_DEFAULT_COMMAND_BUFFER_SIZE (4*1024)\n#endif\n\n#ifndef NK_BUFFER_DEFAULT_INITIAL_SIZE\n#define NK_BUFFER_DEFAULT_INITIAL_SIZE (4*1024)\n#endif\n\n/* standard library headers */\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\n#include <stdlib.h> /* malloc, free */\n#endif\n#ifdef NK_INCLUDE_STANDARD_IO\n#include <stdio.h> /* fopen, fclose,... */\n#endif\n#ifdef NK_INCLUDE_STANDARD_VARARGS\n#include <stdarg.h> /* valist, va_start, va_end, ... */\n#endif\n#ifndef NK_ASSERT\n#include <assert.h>\n#define NK_ASSERT(expr) assert(expr)\n#endif\n\n#define NK_DEFAULT (-1)\n\n#ifndef NK_VSNPRINTF\n/* If your compiler does support `vsnprintf` I would highly recommend\n * defining this to vsnprintf instead since `vsprintf` is basically\n * unbelievable unsafe and should *NEVER* be used. But I have to support\n * it since C89 only provides this unsafe version. */\n  #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) ||\\\n      (defined(__cplusplus) && (__cplusplus >= 201103L)) || \\\n      (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) ||\\\n      (defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) ||\\\n       defined(_ISOC99_SOURCE) || defined(_BSD_SOURCE)\n      #define NK_VSNPRINTF(s,n,f,a) vsnprintf(s,n,f,a)\n  #else\n    #define NK_VSNPRINTF(s,n,f,a) vsprintf(s,f,a)\n  #endif\n#endif\n\n#define NK_SCHAR_MIN (-127)\n#define NK_SCHAR_MAX 127\n#define NK_UCHAR_MIN 0\n#define NK_UCHAR_MAX 256\n#define NK_SSHORT_MIN (-32767)\n#define NK_SSHORT_MAX 32767\n#define NK_USHORT_MIN 0\n#define NK_USHORT_MAX 65535\n#define NK_SINT_MIN (-2147483647)\n#define NK_SINT_MAX 2147483647\n#define NK_UINT_MIN 0\n#define NK_UINT_MAX 4294967295u\n\n/* Make sure correct type size:\n * This will fire with a negative subscript error if the type sizes\n * are set incorrectly by the compiler, and compile out if not */\nNK_STATIC_ASSERT(sizeof(nk_size) >= sizeof(void*));\nNK_STATIC_ASSERT(sizeof(nk_ptr) == sizeof(void*));\nNK_STATIC_ASSERT(sizeof(nk_flags) >= 4);\nNK_STATIC_ASSERT(sizeof(nk_rune) >= 4);\nNK_STATIC_ASSERT(sizeof(nk_ushort) == 2);\nNK_STATIC_ASSERT(sizeof(nk_short) == 2);\nNK_STATIC_ASSERT(sizeof(nk_uint) == 4);\nNK_STATIC_ASSERT(sizeof(nk_int) == 4);\nNK_STATIC_ASSERT(sizeof(nk_byte) == 1);\nNK_STATIC_ASSERT(sizeof(nk_bool) <= sizeof(int));\n\nNK_GLOBAL const struct nk_rect nk_null_rect = {-8192.0f, -8192.0f, 16384, 16384};\n#define NK_FLOAT_PRECISION 0.00000000000001\n\nNK_GLOBAL const struct nk_color nk_red = {255,0,0,255};\nNK_GLOBAL const struct nk_color nk_green = {0,255,0,255};\nNK_GLOBAL const struct nk_color nk_blue = {0,0,255,255};\nNK_GLOBAL const struct nk_color nk_white = {255,255,255,255};\nNK_GLOBAL const struct nk_color nk_black = {0,0,0,255};\nNK_GLOBAL const struct nk_color nk_yellow = {255,255,0,255};\n\n/* widget */\n#define nk_widget_state_reset(s)\\\n    if ((*(s)) & NK_WIDGET_STATE_MODIFIED)\\\n        (*(s)) = NK_WIDGET_STATE_INACTIVE|NK_WIDGET_STATE_MODIFIED;\\\n    else (*(s)) = NK_WIDGET_STATE_INACTIVE;\n\n/* math */\n#ifndef NK_INV_SQRT\n#define NK_INV_SQRT nk_inv_sqrt\n#define NK_INV_SQRT_NEEDED\nNK_LIB float nk_inv_sqrt(float n);\n#endif\n#ifndef NK_SIN\n#define NK_SIN nk_sin\n#define NK_SIN_NEEDED\nNK_LIB float nk_sin(float x);\n#endif\n#ifndef NK_COS\n#define NK_COS nk_cos\n#define NK_COS_NEEDED\nNK_LIB float nk_cos(float x);\n#endif\n#ifndef NK_ATAN\n#define NK_ATAN nk_atan\n#define NK_ATAN_NEEDED\nNK_LIB float nk_atan(float x);\n#endif\n#ifndef NK_ATAN2\n#define NK_ATAN2 nk_atan2\n#define NK_ATAN2_NEEDED\nNK_LIB float nk_atan2(float y, float x);\n#endif\nNK_LIB nk_uint nk_round_up_pow2(nk_uint v);\nNK_LIB struct nk_rect nk_shrink_rect(struct nk_rect r, float amount);\nNK_LIB struct nk_rect nk_pad_rect(struct nk_rect r, struct nk_vec2 pad);\nNK_LIB void nk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0, float x1, float y1);\nNK_LIB int nk_ifloorf(float x);\nNK_LIB int nk_iceilf(float x);\nNK_LIB float nk_roundf(float x);\n\n/* util */\nenum {NK_DO_NOT_STOP_ON_NEW_LINE, NK_STOP_ON_NEW_LINE};\nNK_LIB nk_bool nk_is_lower(int c);\nNK_LIB nk_bool nk_is_upper(int c);\nNK_LIB int nk_to_upper(int c);\nNK_LIB int nk_to_lower(int c);\n\n#ifndef NK_MEMCPY\n#define NK_MEMCPY nk_memcopy\n#define NK_MEMCPY_NEEDED\nNK_LIB void* nk_memcopy(void *dst, const void *src, nk_size n);\n#endif\n#ifndef NK_MEMSET\n#define NK_MEMSET nk_memset\n#define NK_MEMSET_NEEDED\nNK_LIB void nk_memset(void *ptr, int c0, nk_size size);\n#endif\nNK_LIB void nk_zero(void *ptr, nk_size size);\nNK_LIB char *nk_itoa(char *s, long n);\nNK_LIB int nk_string_float_limit(char *string, int prec);\n#ifndef NK_DTOA\n#define NK_DTOA nk_dtoa\n#define NK_DTOA_NEEDED\nNK_LIB char *nk_dtoa(char *s, double n);\n#endif\nNK_LIB int nk_text_clamp(const struct nk_user_font *font, const char *text, int text_len, float space, int *glyphs, float *text_width, nk_rune *sep_list, int sep_count);\nNK_LIB struct nk_vec2 nk_text_calculate_text_bounds(const struct nk_user_font *font, const char *begin, int byte_len, float row_height, const char **remaining, struct nk_vec2 *out_offset, int *glyphs, int op);\n#ifdef NK_INCLUDE_STANDARD_VARARGS\nNK_LIB int nk_strfmt(char *buf, int buf_size, const char *fmt, va_list args);\n#endif\n#ifdef NK_INCLUDE_STANDARD_IO\nNK_LIB char *nk_file_load(const char* path, nk_size* siz, const struct nk_allocator *alloc);\n#endif\n\n/* math helpers that are only used by nk_dtoa */\n#ifdef NK_DTOA_NEEDED\nNK_LIB double nk_pow(double x, int n);\nNK_LIB int nk_ifloord(double x);\nNK_LIB int nk_log10(double n);\n#endif\n\n/* buffer */\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_LIB void* nk_malloc(nk_handle unused, void *old,nk_size size);\nNK_LIB void nk_mfree(nk_handle unused, void *ptr);\n#endif\nNK_LIB void* nk_buffer_align(void *unaligned, nk_size align, nk_size *alignment, enum nk_buffer_allocation_type type);\nNK_LIB void* nk_buffer_alloc(struct nk_buffer *b, enum nk_buffer_allocation_type type, nk_size size, nk_size align);\nNK_LIB void* nk_buffer_realloc(struct nk_buffer *b, nk_size capacity, nk_size *size);\n\n/* draw */\nNK_LIB void nk_command_buffer_init(struct nk_command_buffer *cb, struct nk_buffer *b, enum nk_command_clipping clip);\nNK_LIB void nk_command_buffer_reset(struct nk_command_buffer *b);\nNK_LIB void* nk_command_buffer_push(struct nk_command_buffer* b, enum nk_command_type t, nk_size size);\nNK_LIB void nk_draw_symbol(struct nk_command_buffer *out, enum nk_symbol_type type, struct nk_rect content, struct nk_color background, struct nk_color foreground, float border_width, const struct nk_user_font *font);\n\n/* buffering */\nNK_LIB void nk_start_buffer(struct nk_context *ctx, struct nk_command_buffer *b);\nNK_LIB void nk_start(struct nk_context *ctx, struct nk_window *win);\nNK_LIB void nk_start_popup(struct nk_context *ctx, struct nk_window *win);\nNK_LIB void nk_finish_popup(struct nk_context *ctx, struct nk_window*);\nNK_LIB void nk_finish_buffer(struct nk_context *ctx, struct nk_command_buffer *b);\nNK_LIB void nk_finish(struct nk_context *ctx, struct nk_window *w);\nNK_LIB void nk_build(struct nk_context *ctx);\n\n/* text editor */\nNK_LIB void nk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type, nk_plugin_filter filter);\nNK_LIB void nk_textedit_click(struct nk_text_edit *state, float x, float y, const struct nk_user_font *font, float row_height);\nNK_LIB void nk_textedit_drag(struct nk_text_edit *state, float x, float y, const struct nk_user_font *font, float row_height);\nNK_LIB void nk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod, const struct nk_user_font *font, float row_height);\n\n/* window */\nenum nk_window_insert_location {\n    NK_INSERT_BACK, /* inserts window into the back of list (front of screen) */\n    NK_INSERT_FRONT /* inserts window into the front of list (back of screen) */\n};\nNK_LIB void *nk_create_window(struct nk_context *ctx);\nNK_LIB void nk_remove_window(struct nk_context*, struct nk_window*);\nNK_LIB void nk_free_window(struct nk_context *ctx, struct nk_window *win);\nNK_LIB struct nk_window *nk_find_window(const struct nk_context *ctx, nk_hash hash, const char *name);\nNK_LIB void nk_insert_window(struct nk_context *ctx, struct nk_window *win, enum nk_window_insert_location loc);\n\n/* pool */\nNK_LIB void nk_pool_init(struct nk_pool *pool, const struct nk_allocator *alloc, unsigned int capacity);\nNK_LIB void nk_pool_free(struct nk_pool *pool);\nNK_LIB void nk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size);\nNK_LIB struct nk_page_element *nk_pool_alloc(struct nk_pool *pool);\n\n/* page-element */\nNK_LIB struct nk_page_element* nk_create_page_element(struct nk_context *ctx);\nNK_LIB void nk_link_page_element_into_freelist(struct nk_context *ctx, struct nk_page_element *elem);\nNK_LIB void nk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem);\n\n/* table */\nNK_LIB struct nk_table* nk_create_table(struct nk_context *ctx);\nNK_LIB void nk_remove_table(struct nk_window *win, struct nk_table *tbl);\nNK_LIB void nk_free_table(struct nk_context *ctx, struct nk_table *tbl);\nNK_LIB void nk_push_table(struct nk_window *win, struct nk_table *tbl);\nNK_LIB nk_uint *nk_add_value(struct nk_context *ctx, struct nk_window *win, nk_hash name, nk_uint value);\nNK_LIB nk_uint *nk_find_value(const struct nk_window *win, nk_hash name);\n\n/* panel */\nNK_LIB void *nk_create_panel(struct nk_context *ctx);\nNK_LIB void nk_free_panel(struct nk_context*, struct nk_panel *pan);\nNK_LIB nk_bool nk_panel_has_header(nk_flags flags, const char *title);\nNK_LIB struct nk_vec2 nk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type);\nNK_LIB float nk_panel_get_border(const struct nk_style *style, nk_flags flags, enum nk_panel_type type);\nNK_LIB struct nk_color nk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type);\nNK_LIB nk_bool nk_panel_is_sub(enum nk_panel_type type);\nNK_LIB nk_bool nk_panel_is_nonblock(enum nk_panel_type type);\nNK_LIB nk_bool nk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type);\nNK_LIB void nk_panel_end(struct nk_context *ctx);\n\n/* layout */\nNK_LIB float nk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type, float total_space, int columns);\nNK_LIB void nk_panel_layout(const struct nk_context *ctx, struct nk_window *win, float height, int cols);\nNK_LIB void nk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt, float height, int cols, int width);\nNK_LIB void nk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win);\nNK_LIB void nk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx, struct nk_window *win, int modify);\nNK_LIB void nk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx);\nNK_LIB void nk_layout_peek(struct nk_rect *bounds, const struct nk_context *ctx);\n\n/* popup */\nNK_LIB nk_bool nk_nonblock_begin(struct nk_context *ctx, nk_flags flags, struct nk_rect body, struct nk_rect header, enum nk_panel_type panel_type);\n\n/* text */\nstruct nk_text {\n    struct nk_vec2 padding;\n    struct nk_color background;\n    struct nk_color text;\n};\nNK_LIB void nk_widget_text(struct nk_command_buffer *o, struct nk_rect b, const char *string, int len, const struct nk_text *t, nk_flags a, const struct nk_user_font *f);\nNK_LIB void nk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b, const char *string, int len, const struct nk_text *t, const struct nk_user_font *f);\n\n/* button */\nNK_LIB nk_bool nk_button_behavior(nk_flags *state, struct nk_rect r, const struct nk_input *i, enum nk_button_behavior behavior);\nNK_LIB const struct nk_style_item* nk_draw_button(struct nk_command_buffer *out, const struct nk_rect *bounds, nk_flags state, const struct nk_style_button *style);\nNK_LIB nk_bool nk_do_button(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, const struct nk_style_button *style, const struct nk_input *in, enum nk_button_behavior behavior, struct nk_rect *content);\nNK_LIB void nk_draw_button_text(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, const char *txt, int len, nk_flags text_alignment, const struct nk_user_font *font);\nNK_LIB nk_bool nk_do_button_text(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *string, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_input *in, const struct nk_user_font *font);\nNK_LIB void nk_draw_button_symbol(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, enum nk_symbol_type type, const struct nk_user_font *font);\nNK_LIB nk_bool nk_do_button_symbol(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, enum nk_symbol_type symbol, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_input *in, const struct nk_user_font *font);\nNK_LIB void nk_draw_button_image(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *content, nk_flags state, const struct nk_style_button *style, const struct nk_image *img);\nNK_LIB nk_bool nk_do_button_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, struct nk_image img, enum nk_button_behavior b, const struct nk_style_button *style, const struct nk_input *in);\nNK_LIB void nk_draw_button_text_symbol(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *label, const struct nk_rect *symbol, nk_flags state, const struct nk_style_button *style, const char *str, int len, enum nk_symbol_type type, const struct nk_user_font *font);\nNK_LIB nk_bool nk_do_button_text_symbol(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, enum nk_symbol_type symbol, const char *str, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_user_font *font, const struct nk_input *in);\nNK_LIB void nk_draw_button_text_image(struct nk_command_buffer *out, const struct nk_rect *bounds, const struct nk_rect *label, const struct nk_rect *image, nk_flags state, const struct nk_style_button *style, const char *str, int len, const struct nk_user_font *font, const struct nk_image *img);\nNK_LIB nk_bool nk_do_button_text_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, struct nk_image img, const char* str, int len, nk_flags align, enum nk_button_behavior behavior, const struct nk_style_button *style, const struct nk_user_font *font, const struct nk_input *in);\n\n/* toggle */\nenum nk_toggle_type {\n    NK_TOGGLE_CHECK,\n    NK_TOGGLE_OPTION\n};\nNK_LIB nk_bool nk_toggle_behavior(const struct nk_input *in, struct nk_rect select, nk_flags *state, nk_bool active);\nNK_LIB void nk_draw_checkbox(struct nk_command_buffer *out, nk_flags state, const struct nk_style_toggle *style, nk_bool active, const struct nk_rect *label, const struct nk_rect *selector, const struct nk_rect *cursors, const char *string, int len, const struct nk_user_font *font, nk_flags text_alignment);\nNK_LIB void nk_draw_option(struct nk_command_buffer *out, nk_flags state, const struct nk_style_toggle *style, nk_bool active, const struct nk_rect *label, const struct nk_rect *selector, const struct nk_rect *cursors, const char *string, int len, const struct nk_user_font *font, nk_flags text_alignment);\nNK_LIB nk_bool nk_do_toggle(nk_flags *state, struct nk_command_buffer *out, struct nk_rect r, nk_bool *active, const char *str, int len, enum nk_toggle_type type, const struct nk_style_toggle *style, const struct nk_input *in, const struct nk_user_font *font, nk_flags widget_alignment, nk_flags text_alignment);\n\n/* progress */\nNK_LIB nk_size nk_progress_behavior(nk_flags *state, struct nk_input *in, struct nk_rect r, struct nk_rect cursor, nk_size max, nk_size value, nk_bool modifiable);\nNK_LIB void nk_draw_progress(struct nk_command_buffer *out, nk_flags state, const struct nk_style_progress *style, const struct nk_rect *bounds, const struct nk_rect *scursor, nk_size value, nk_size max);\nNK_LIB nk_size nk_do_progress(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, nk_size value, nk_size max, nk_bool modifiable, const struct nk_style_progress *style, struct nk_input *in);\n\n/* slider */\nNK_LIB float nk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor, struct nk_rect *visual_cursor, struct nk_input *in, struct nk_rect bounds, float slider_min, float slider_max, float slider_value, float slider_step, float slider_steps);\nNK_LIB void nk_draw_slider(struct nk_command_buffer *out, nk_flags state, const struct nk_style_slider *style, const struct nk_rect *bounds, const struct nk_rect *visual_cursor, float min, float value, float max);\nNK_LIB float nk_do_slider(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, float min, float val, float max, float step, const struct nk_style_slider *style, struct nk_input *in, const struct nk_user_font *font);\n\n/* scrollbar */\nNK_LIB float nk_scrollbar_behavior(nk_flags *state, struct nk_input *in, int has_scrolling, const struct nk_rect *scroll, const struct nk_rect *cursor, const struct nk_rect *empty0, const struct nk_rect *empty1, float scroll_offset, float target, float scroll_step, enum nk_orientation o);\nNK_LIB void nk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state, const struct nk_style_scrollbar *style, const struct nk_rect *bounds, const struct nk_rect *scroll);\nNK_LIB float nk_do_scrollbarv(nk_flags *state, struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, float offset, float target, float step, float button_pixel_inc, const struct nk_style_scrollbar *style, struct nk_input *in, const struct nk_user_font *font);\nNK_LIB float nk_do_scrollbarh(nk_flags *state, struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling, float offset, float target, float step, float button_pixel_inc, const struct nk_style_scrollbar *style, struct nk_input *in, const struct nk_user_font *font);\n\n/* selectable */\nNK_LIB void nk_draw_selectable(struct nk_command_buffer *out, nk_flags state, const struct nk_style_selectable *style, nk_bool active, const struct nk_rect *bounds, const struct nk_rect *icon, const struct nk_image *img, enum nk_symbol_type sym, const char *string, int len, nk_flags align, const struct nk_user_font *font);\nNK_LIB nk_bool nk_do_selectable(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, const struct nk_style_selectable *style, const struct nk_input *in, const struct nk_user_font *font);\nNK_LIB nk_bool nk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value, const struct nk_image *img, const struct nk_style_selectable *style, const struct nk_input *in, const struct nk_user_font *font);\n\n/* edit */\nNK_LIB void nk_edit_draw_text(struct nk_command_buffer *out, const struct nk_style_edit *style, float pos_x, float pos_y, float x_offset, const char *text, int byte_len, float row_height, const struct nk_user_font *font, struct nk_color background, struct nk_color foreground, nk_bool is_selected);\nNK_LIB nk_flags nk_do_edit(nk_flags *state, struct nk_command_buffer *out, struct nk_rect bounds, nk_flags flags, nk_plugin_filter filter, struct nk_text_edit *edit, const struct nk_style_edit *style, struct nk_input *in, const struct nk_user_font *font);\n\n/* color-picker */\nNK_LIB nk_bool nk_color_picker_behavior(nk_flags *state, const struct nk_rect *bounds, const struct nk_rect *matrix, const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, struct nk_colorf *color, const struct nk_input *in);\nNK_LIB void nk_draw_color_picker(struct nk_command_buffer *o, const struct nk_rect *matrix, const struct nk_rect *hue_bar, const struct nk_rect *alpha_bar, struct nk_colorf col);\nNK_LIB nk_bool nk_do_color_picker(nk_flags *state, struct nk_command_buffer *out, struct nk_colorf *col, enum nk_color_format fmt, struct nk_rect bounds, struct nk_vec2 padding, const struct nk_input *in, const struct nk_user_font *font);\n\n/* property */\nenum nk_property_status {\n    NK_PROPERTY_DEFAULT,\n    NK_PROPERTY_EDIT,\n    NK_PROPERTY_DRAG\n};\nenum nk_property_filter {\n    NK_FILTER_INT,\n    NK_FILTER_FLOAT\n};\nenum nk_property_kind {\n    NK_PROPERTY_INT,\n    NK_PROPERTY_FLOAT,\n    NK_PROPERTY_DOUBLE\n};\nunion nk_property {\n    int i;\n    float f;\n    double d;\n};\nstruct nk_property_variant {\n    enum nk_property_kind kind;\n    union nk_property value;\n    union nk_property min_value;\n    union nk_property max_value;\n    union nk_property step;\n};\nNK_LIB struct nk_property_variant nk_property_variant_int(int value, int min_value, int max_value, int step);\nNK_LIB struct nk_property_variant nk_property_variant_float(float value, float min_value, float max_value, float step);\nNK_LIB struct nk_property_variant nk_property_variant_double(double value, double min_value, double max_value, double step);\n\nNK_LIB void nk_drag_behavior(nk_flags *state, const struct nk_input *in, struct nk_rect drag, struct nk_property_variant *variant, float inc_per_pixel);\nNK_LIB void nk_property_behavior(nk_flags *ws, const struct nk_input *in, struct nk_rect property,  struct nk_rect label, struct nk_rect edit, struct nk_rect empty, int *state, struct nk_property_variant *variant, float inc_per_pixel);\nNK_LIB void nk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style, const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state, const char *name, int len, const struct nk_user_font *font);\nNK_LIB void nk_do_property(nk_flags *ws, struct nk_command_buffer *out, struct nk_rect property, const char *name, struct nk_property_variant *variant, float inc_per_pixel, char *buffer, int *len, int *state, int *cursor, int *select_begin, int *select_end, const struct nk_style_property *style, enum nk_property_filter filter, struct nk_input *in, const struct nk_user_font *font, struct nk_text_edit *text_edit, enum nk_button_behavior behavior);\nNK_LIB void nk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant, float inc_per_pixel, const enum nk_property_filter filter);\n\n#ifdef NK_INCLUDE_FONT_BAKING\n\n/**\n * @def NK_NO_STB_RECT_PACK_IMPLEMENTATION\n *\n * When defined, will avoid enabling STB_RECT_PACK_IMPLEMENTATION for when stb_rect_pack.h is already implemented elsewhere.\n */\n#ifndef NK_NO_STB_RECT_PACK_IMPLEMENTATION\n#define STB_RECT_PACK_IMPLEMENTATION\n#endif /* NK_NO_STB_RECT_PACK_IMPLEMENTATION */\n\n/**\n * @def NK_NO_STB_TRUETYPE_IMPLEMENTATION\n *\n * When defined, will avoid enabling STB_TRUETYPE_IMPLEMENTATION for when stb_truetype.h is already implemented elsewhere.\n */\n#ifndef NK_NO_STB_TRUETYPE_IMPLEMENTATION\n#define STB_TRUETYPE_IMPLEMENTATION\n#endif /* NK_NO_STB_TRUETYPE_IMPLEMENTATION */\n\n/* Allow consumer to define own STBTT_malloc/STBTT_free, and use the font atlas' allocator otherwise */\n#ifndef STBTT_malloc\nstatic void*\nnk_stbtt_malloc(nk_size size, void *user_data) {\n    struct nk_allocator *alloc = (struct nk_allocator *) user_data;\n    return alloc->alloc(alloc->userdata, 0, size);\n}\n\nstatic void\nnk_stbtt_free(void *ptr, void *user_data) {\n    struct nk_allocator *alloc = (struct nk_allocator *) user_data;\n    alloc->free(alloc->userdata, ptr);\n}\n\n#define STBTT_malloc(x,u)  nk_stbtt_malloc(x,u)\n#define STBTT_free(x,u)    nk_stbtt_free(x,u)\n\n#endif /* STBTT_malloc */\n\n#endif /* NK_INCLUDE_FONT_BAKING */\n\n#endif\n"
  },
  {
    "path": "src/nuklear_knob.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                               KNOB\n *\n * ===============================================================*/\n\nNK_LIB float\nnk_knob_behavior(nk_flags *state, struct nk_input *in,\n    struct nk_rect bounds, float knob_min, float knob_max, float knob_value,\n    float knob_step, float knob_steps,\n    enum nk_heading zero_direction, float dead_zone_percent)\n{\n    struct nk_vec2 origin;\n    float angle = 0.0f;\n    origin.x = bounds.x + (bounds.w / 2);\n    origin.y = bounds.y + (bounds.h / 2);\n\n    nk_widget_state_reset(state);\n\n    /* handle click and drag input */\n    if(in &&\n       in->mouse.buttons[NK_BUTTON_LEFT].down &&\n       nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, bounds, nk_true)){\n        /* calculate angle from origin and rotate */\n        const float direction_rads[4] = {\n            NK_PI * 2.5f, /* 90  NK_UP */\n            NK_PI * 2.0f, /* 0   NK_RIGHT */\n            NK_PI * 1.5f, /* 270 NK_DOWN */\n            NK_PI,        /* 180 NK_LEFT */\n        };\n        *state = NK_WIDGET_STATE_ACTIVE;\n\n        angle = NK_ATAN2(in->mouse.pos.y - origin.y, in->mouse.pos.x - origin.x) + direction_rads[zero_direction];\n        angle -= (angle > NK_PI * 2) ? NK_PI * 3 : NK_PI;\n\n        /* account for dead space applied when drawing */\n        angle *= 1.0f / (1.0f - dead_zone_percent);\n        angle = NK_CLAMP(-NK_PI, angle, NK_PI);\n\n        /* convert -pi -> pi range to 0.0 -> 1.0 */\n        angle = (angle + NK_PI) / (NK_PI * 2);\n\n        /* click to closest step */\n        knob_value = knob_min + ( (int)(angle * knob_steps + (knob_step / 2)) ) * knob_step;\n        knob_value = NK_CLAMP(knob_min, knob_value, knob_max);\n    }\n\n    /* knob widget state */\n    if (nk_input_is_mouse_hovering_rect(in, bounds)){\n        *state = NK_WIDGET_STATE_HOVERED;\n        /* handle scroll and arrow inputs */\n        if (in->mouse.scroll_delta.y > 0 ||\n           (in->keyboard.keys[NK_KEY_UP].down && in->keyboard.keys[NK_KEY_UP].clicked)) {\n            knob_value += knob_step;\n        }\n\n        if (in->mouse.scroll_delta.y < 0 ||\n           (in->keyboard.keys[NK_KEY_DOWN].down && in->keyboard.keys[NK_KEY_DOWN].clicked)) {\n            knob_value -= knob_step;\n        }\n        /* easiest way to disable scrolling of parent panels..knob eats scrolling */\n        in->mouse.scroll_delta.y = 0;\n        knob_value = NK_CLAMP(knob_min, knob_value, knob_max);\n    }\n    if (*state & NK_WIDGET_STATE_HOVER &&\n        !nk_input_is_mouse_prev_hovering_rect(in, bounds))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, bounds))\n        *state |= NK_WIDGET_STATE_LEFT;\n\n    return knob_value;\n}\nNK_LIB void\nnk_draw_knob(struct nk_command_buffer *out, nk_flags state,\n    const struct nk_style_knob *style, const struct nk_rect *bounds, float min, float value, float max,\n    enum nk_heading zero_direction, float dead_zone_percent)\n{\n    const struct nk_style_item *background;\n    struct nk_color knob_color, cursor;\n\n    NK_UNUSED(min);\n    NK_UNUSED(max);\n    NK_UNUSED(value);\n\n    if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->active;\n        knob_color = style->knob_active;\n        cursor = style->cursor_active;\n    } else if (state & NK_WIDGET_STATE_HOVER) {\n        background = &style->hover;\n        knob_color = style->knob_hover;\n        cursor = style->cursor_hover;\n    } else {\n        background = &style->normal;\n        knob_color = style->knob_normal;\n        cursor = style->cursor_normal;\n    }\n\n    /* draw background */\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *bounds, 0, nk_rgb_factor(background->data.color, style->color_factor));\n            nk_stroke_rect(out, *bounds, 0, style->border, nk_rgb_factor(style->border_color, style->color_factor));\n            break;\n    }\n\n    /* draw knob */\n    nk_fill_circle(out, *bounds, nk_rgb_factor(knob_color, style->color_factor));\n    if(style->knob_border > 0){\n        struct nk_rect border_bounds = *bounds;\n        border_bounds.x += style->knob_border / 2;\n        border_bounds.y += style->knob_border / 2;\n        border_bounds.w -= style->knob_border;\n        border_bounds.h -= style->knob_border;\n        nk_stroke_circle(out, border_bounds, style->knob_border, nk_rgb_factor(style->knob_border_color, style->color_factor));\n    }\n    { /* calculate cursor line cords */\n    float half_circle_size = (bounds->w / 2);\n    float angle = (value - min) / (max - min);\n    float alive_zone =  1.0f - dead_zone_percent;\n    struct nk_vec2 cursor_start, cursor_end;\n    const float direction_rads[4] = {\n        NK_PI * 1.5f, /* 90  NK_UP */\n        0.0f,         /* 0   NK_RIGHT */\n        NK_PI * 0.5f, /* 270 NK_DOWN */\n        NK_PI,        /* 180 NK_LEFT */\n    };\n    /* calculate + apply dead zone */\n    angle = (angle * alive_zone) + (dead_zone_percent / 2);\n\n    /* percentage 0.0 -> 1.0 to radians, rads are 0.0 to (2*pi) NOT -pi to pi */\n    angle *= NK_PI * 2;\n\n    /* apply zero angle */\n    angle += direction_rads[zero_direction];\n    if(angle > NK_PI * 2)\n        angle -= NK_PI * 2;\n\n    cursor_start.x = bounds->x + half_circle_size + (angle > NK_PI);\n    cursor_start.y = bounds->y + half_circle_size + (angle < NK_PI_HALF || angle > (NK_PI * 1.5f));\n\n    cursor_end.x = cursor_start.x + (half_circle_size * NK_COS(angle));\n    cursor_end.y = cursor_start.y + (half_circle_size * NK_SIN(angle));\n\n    /* cut off half of the cursor */\n    cursor_start.x = (cursor_start.x + cursor_end.x) / 2;\n    cursor_start.y = (cursor_start.y + cursor_end.y) / 2;\n\n    /* draw cursor */\n    nk_stroke_line(out, cursor_start.x, cursor_start.y, cursor_end.x, cursor_end.y, 2, nk_rgb_factor(cursor, style->color_factor));\n    }\n}\nNK_LIB float\nnk_do_knob(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    float min, float val, float max, float step,\n    enum nk_heading zero_direction, float dead_zone_percent,\n    const struct nk_style_knob *style, struct nk_input *in)\n{\n    float knob_range;\n    float knob_min;\n    float knob_max;\n    float knob_value;\n    float knob_steps;\n\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    if (!out || !style)\n        return 0;\n\n    /* remove padding from knob bounds */\n    bounds.y = bounds.y + style->padding.y;\n    bounds.x = bounds.x + style->padding.x;\n    bounds.h = NK_MAX(bounds.h, 2*style->padding.y);\n    bounds.w = NK_MAX(bounds.w, 2*style->padding.x);\n    bounds.w -= 2 * style->padding.x;\n    bounds.h -= 2 * style->padding.y;\n    if(bounds.h < bounds.w){\n        bounds.x += (bounds.w - bounds.h) / 2;\n        bounds.w = bounds.h;\n    }\n\n    /* make sure the provided values are correct */\n    knob_max = NK_MAX(min, max);\n    knob_min = NK_MIN(min, max);\n    knob_value = NK_CLAMP(knob_min, val, knob_max);\n    knob_range = knob_max - knob_min;\n    knob_steps = knob_range / step;\n\n    knob_value = nk_knob_behavior(state, in, bounds, knob_min, knob_max, knob_value, step, knob_steps, zero_direction, dead_zone_percent);\n\n    /* draw knob */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_knob(out, *state, style, &bounds, knob_min, knob_value, knob_max, zero_direction, dead_zone_percent);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return knob_value;\n}\nNK_API nk_bool\nnk_knob_float(struct nk_context *ctx, float min_value, float *value, float max_value,\n    float value_step, enum nk_heading zero_direction, float dead_zone_degrees)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    struct nk_input *in;\n    const struct nk_style *style;\n\n    int ret = 0;\n    float old_value;\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    NK_ASSERT(value);\n    NK_ASSERT(NK_BETWEEN(dead_zone_degrees, 0.0f, 360.0f));\n    if (!ctx || !ctx->current || !ctx->current->layout || !value)\n        return ret;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return ret;\n    in = (state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n\n    old_value = *value;\n    *value = nk_do_knob(&ctx->last_widget_state, &win->buffer, bounds, min_value,\n                old_value, max_value, value_step, zero_direction, dead_zone_degrees / 360.0f, &style->knob, in);\n\n    return (old_value > *value || old_value < *value);\n}\nNK_API nk_bool\nnk_knob_int(struct nk_context *ctx, int min, int *val, int max, int step,\n    enum nk_heading zero_direction, float dead_zone_degrees)\n{\n    int ret;\n    float value = (float)*val;\n    ret = nk_knob_float(ctx, (float)min, &value, (float)max, (float)step, zero_direction, dead_zone_degrees);\n    *val =  (int)value;\n    return ret;\n}\n"
  },
  {
    "path": "src/nuklear_layout.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                          LAYOUT\n *\n * ===============================================================*/\nNK_API void\nnk_layout_set_min_row_height(struct nk_context *ctx, float height)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    layout->row.min_height = height;\n}\nNK_API void\nnk_layout_reset_min_row_height(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    layout->row.min_height = ctx->style.font->height;\n    layout->row.min_height += ctx->style.text.padding.y*2;\n    layout->row.min_height += ctx->style.window.min_row_height_padding*2;\n}\nNK_LIB float\nnk_layout_row_calculate_usable_space(const struct nk_style *style, enum nk_panel_type type,\n    float total_space, int columns)\n{\n    float panel_spacing;\n    float panel_space;\n\n    struct nk_vec2 spacing;\n\n    NK_UNUSED(type);\n\n    spacing = style->window.spacing;\n\n    /* calculate the usable panel space */\n    panel_spacing = (float)NK_MAX(columns - 1, 0) * spacing.x;\n    panel_space  = total_space - panel_spacing;\n    return panel_space;\n}\nNK_LIB void\nnk_panel_layout(const struct nk_context *ctx, struct nk_window *win,\n    float height, int cols)\n{\n    struct nk_panel *layout;\n    const struct nk_style *style;\n    struct nk_command_buffer *out;\n\n    struct nk_vec2 item_spacing;\n    struct nk_color color;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    /* prefetch some configuration data */\n    layout = win->layout;\n    style = &ctx->style;\n    out = &win->buffer;\n    color = style->window.background;\n    item_spacing = style->window.spacing;\n\n    /*  if one of these triggers you forgot to add an `if` condition around either\n        a window, group, popup, combobox or contextual menu `begin` and `end` block.\n        Example:\n            if (nk_begin(...) {...} nk_end(...); or\n            if (nk_group_begin(...) { nk_group_end(...);} */\n    NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));\n    NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));\n    NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));\n\n    /* update the current row and set the current row layout */\n    layout->row.index = 0;\n    layout->at_y += layout->row.height;\n    layout->row.columns = cols;\n    if (height == 0.0f)\n        layout->row.height = NK_MAX(height, layout->row.min_height) + item_spacing.y;\n    else layout->row.height = height + item_spacing.y;\n\n    layout->row.item_offset = 0;\n    if (layout->flags & NK_WINDOW_DYNAMIC) {\n        /* draw background for dynamic panels */\n        struct nk_rect background;\n        background.x = win->bounds.x;\n        background.w = win->bounds.w;\n        background.y = layout->at_y - 1.0f;\n        background.h = layout->row.height + 1.0f;\n        nk_fill_rect(out, background, 0, color);\n    }\n}\nNK_LIB void\nnk_row_layout(struct nk_context *ctx, enum nk_layout_format fmt,\n    float height, int cols, int width)\n{\n    /* update the current row and set the current row layout */\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    nk_panel_layout(ctx, win, height, cols);\n    if (fmt == NK_DYNAMIC)\n        win->layout->row.type = NK_LAYOUT_DYNAMIC_FIXED;\n    else win->layout->row.type = NK_LAYOUT_STATIC_FIXED;\n\n    win->layout->row.ratio = 0;\n    win->layout->row.filled = 0;\n    win->layout->row.item_offset = 0;\n    win->layout->row.item_width = (float)width;\n}\nNK_API float\nnk_layout_ratio_from_pixel(const struct nk_context *ctx, float pixel_width)\n{\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    NK_ASSERT(pixel_width);\n    if (!ctx || !ctx->current || !ctx->current->layout) return 0;\n    win = ctx->current;\n    return NK_CLAMP(0.0f, pixel_width/win->bounds.x, 1.0f);\n}\nNK_API void\nnk_layout_row_dynamic(struct nk_context *ctx, float height, int cols)\n{\n    nk_row_layout(ctx, NK_DYNAMIC, height, cols, 0);\n}\nNK_API void\nnk_layout_row_static(struct nk_context *ctx, float height, int item_width, int cols)\n{\n    nk_row_layout(ctx, NK_STATIC, height, cols, item_width);\n}\nNK_API void\nnk_layout_row_begin(struct nk_context *ctx, enum nk_layout_format fmt,\n    float row_height, int cols)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    nk_panel_layout(ctx, win, row_height, cols);\n    if (fmt == NK_DYNAMIC)\n        layout->row.type = NK_LAYOUT_DYNAMIC_ROW;\n    else layout->row.type = NK_LAYOUT_STATIC_ROW;\n\n    layout->row.ratio = 0;\n    layout->row.filled = 0;\n    layout->row.item_width = 0;\n    layout->row.item_offset = 0;\n    layout->row.columns = cols;\n}\nNK_API void\nnk_layout_row_push(struct nk_context *ctx, float ratio_or_width)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);\n    if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)\n        return;\n\n    if (layout->row.type == NK_LAYOUT_DYNAMIC_ROW) {\n        float ratio = ratio_or_width;\n        if ((ratio + layout->row.filled) > 1.0f) return;\n        if (ratio > 0.0f)\n            layout->row.item_width = NK_SATURATE(ratio);\n        else layout->row.item_width = 1.0f - layout->row.filled;\n    } else layout->row.item_width = ratio_or_width;\n}\nNK_API void\nnk_layout_row_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    NK_ASSERT(layout->row.type == NK_LAYOUT_STATIC_ROW || layout->row.type == NK_LAYOUT_DYNAMIC_ROW);\n    if (layout->row.type != NK_LAYOUT_STATIC_ROW && layout->row.type != NK_LAYOUT_DYNAMIC_ROW)\n        return;\n    layout->row.item_width = 0;\n    layout->row.item_offset = 0;\n}\nNK_API void\nnk_layout_row(struct nk_context *ctx, enum nk_layout_format fmt,\n    float height, int cols, const float *ratio)\n{\n    int i;\n    int n_undef = 0;\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    nk_panel_layout(ctx, win, height, cols);\n    if (fmt == NK_DYNAMIC) {\n        /* calculate width of undefined widget ratios */\n        float r = 0;\n        layout->row.ratio = ratio;\n        for (i = 0; i < cols; ++i) {\n            if (ratio[i] < 0.0f)\n                n_undef++;\n            else r += ratio[i];\n        }\n        r = NK_SATURATE(1.0f - r);\n        layout->row.type = NK_LAYOUT_DYNAMIC;\n        layout->row.item_width = (r > 0 && n_undef > 0) ? (r / (float)n_undef):0;\n    } else {\n        layout->row.ratio = ratio;\n        layout->row.type = NK_LAYOUT_STATIC;\n        layout->row.item_width = 0;\n        layout->row.item_offset = 0;\n    }\n    layout->row.item_offset = 0;\n    layout->row.filled = 0;\n}\nNK_API void\nnk_layout_row_template_begin(struct nk_context *ctx, float height)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    nk_panel_layout(ctx, win, height, 1);\n    layout->row.type = NK_LAYOUT_TEMPLATE;\n    layout->row.columns = 0;\n    layout->row.ratio = 0;\n    layout->row.item_width = 0;\n    layout->row.item_height = 0;\n    layout->row.item_offset = 0;\n    layout->row.filled = 0;\n    layout->row.item.x = 0;\n    layout->row.item.y = 0;\n    layout->row.item.w = 0;\n    layout->row.item.h = 0;\n}\nNK_API void\nnk_layout_row_template_push_dynamic(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);\n    NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);\n    if (layout->row.type != NK_LAYOUT_TEMPLATE) return;\n    if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;\n    layout->row.templates[layout->row.columns++] = -1.0f;\n}\nNK_API void\nnk_layout_row_template_push_variable(struct nk_context *ctx, float min_width)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);\n    NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);\n    if (layout->row.type != NK_LAYOUT_TEMPLATE) return;\n    if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;\n    layout->row.templates[layout->row.columns++] = -min_width;\n}\nNK_API void\nnk_layout_row_template_push_static(struct nk_context *ctx, float width)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);\n    NK_ASSERT(layout->row.columns < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);\n    if (layout->row.type != NK_LAYOUT_TEMPLATE) return;\n    if (layout->row.columns >= NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS) return;\n    layout->row.templates[layout->row.columns++] = width;\n}\nNK_API void\nnk_layout_row_template_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    int i = 0;\n    int variable_count = 0;\n    int min_variable_count = 0;\n    float min_fixed_width = 0.0f;\n    float total_fixed_width = 0.0f;\n    float max_variable_width = 0.0f;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    NK_ASSERT(layout->row.type == NK_LAYOUT_TEMPLATE);\n    if (layout->row.type != NK_LAYOUT_TEMPLATE) return;\n    for (i = 0; i < layout->row.columns; ++i) {\n        float width = layout->row.templates[i];\n        if (width >= 0.0f) {\n            total_fixed_width += width;\n            min_fixed_width += width;\n        } else if (width < -1.0f) {\n            width = -width;\n            total_fixed_width += width;\n            max_variable_width = NK_MAX(max_variable_width, width);\n            variable_count++;\n        } else {\n            min_variable_count++;\n            variable_count++;\n        }\n    }\n    if (variable_count) {\n        float space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,\n                            layout->bounds.w, layout->row.columns);\n        float var_width = (NK_MAX(space-min_fixed_width,0.0f)) / (float)variable_count;\n        int enough_space = var_width >= max_variable_width;\n        if (!enough_space)\n            var_width = (NK_MAX(space-total_fixed_width,0)) / (float)min_variable_count;\n        for (i = 0; i < layout->row.columns; ++i) {\n            float *width = &layout->row.templates[i];\n            *width = (*width >= 0.0f)? *width: (*width < -1.0f && !enough_space)? -(*width): var_width;\n        }\n    }\n}\nNK_API void\nnk_layout_space_begin(struct nk_context *ctx, enum nk_layout_format fmt,\n    float height, int widget_count)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    nk_panel_layout(ctx, win, height, widget_count);\n    if (fmt == NK_STATIC)\n        layout->row.type = NK_LAYOUT_STATIC_FREE;\n    else layout->row.type = NK_LAYOUT_DYNAMIC_FREE;\n\n    layout->row.ratio = 0;\n    layout->row.filled = 0;\n    layout->row.item_width = 0;\n    layout->row.item_offset = 0;\n}\nNK_API void\nnk_layout_space_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    layout->row.item_width = 0;\n    layout->row.item_height = 0;\n    layout->row.item_offset = 0;\n    nk_zero(&layout->row.item, sizeof(layout->row.item));\n}\nNK_API void\nnk_layout_space_push(struct nk_context *ctx, struct nk_rect rect)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    layout->row.item = rect;\n}\nNK_API struct nk_rect\nnk_layout_space_bounds(const struct nk_context *ctx)\n{\n    struct nk_rect ret;\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    win = ctx->current;\n    layout = win->layout;\n\n    ret.x = layout->clip.x;\n    ret.y = layout->clip.y;\n    ret.w = layout->clip.w;\n    ret.h = layout->row.height;\n    return ret;\n}\nNK_API struct nk_rect\nnk_layout_widget_bounds(const struct nk_context *ctx)\n{\n    struct nk_rect ret;\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    win = ctx->current;\n    layout = win->layout;\n\n    ret.x = layout->at_x;\n    ret.y = layout->at_y;\n    ret.w = layout->bounds.w - NK_MAX(layout->at_x - layout->bounds.x,0);\n    ret.h = layout->row.height;\n    return ret;\n}\nNK_API struct nk_vec2\nnk_layout_space_to_screen(const struct nk_context *ctx, struct nk_vec2 ret)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    win = ctx->current;\n    layout = win->layout;\n\n    ret.x += layout->at_x - (float)*layout->offset_x;\n    ret.y += layout->at_y - (float)*layout->offset_y;\n    return ret;\n}\nNK_API struct nk_vec2\nnk_layout_space_to_local(const struct nk_context *ctx, struct nk_vec2 ret)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    win = ctx->current;\n    layout = win->layout;\n\n    ret.x += -layout->at_x + (float)*layout->offset_x;\n    ret.y += -layout->at_y + (float)*layout->offset_y;\n    return ret;\n}\nNK_API struct nk_rect\nnk_layout_space_rect_to_screen(const struct nk_context *ctx, struct nk_rect ret)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    win = ctx->current;\n    layout = win->layout;\n\n    ret.x += layout->at_x - (float)*layout->offset_x;\n    ret.y += layout->at_y - (float)*layout->offset_y;\n    return ret;\n}\nNK_API struct nk_rect\nnk_layout_space_rect_to_local(const struct nk_context *ctx, struct nk_rect ret)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    win = ctx->current;\n    layout = win->layout;\n\n    ret.x += -layout->at_x + (float)*layout->offset_x;\n    ret.y += -layout->at_y + (float)*layout->offset_y;\n    return ret;\n}\nNK_LIB void\nnk_panel_alloc_row(const struct nk_context *ctx, struct nk_window *win)\n{\n    struct nk_panel *layout = win->layout;\n    struct nk_vec2 spacing = ctx->style.window.spacing;\n    const float row_height = layout->row.height - spacing.y;\n    nk_panel_layout(ctx, win, row_height, layout->row.columns);\n}\nNK_LIB void\nnk_layout_widget_space(struct nk_rect *bounds, const struct nk_context *ctx,\n    struct nk_window *win, int modify)\n{\n    struct nk_panel *layout;\n    const struct nk_style *style;\n\n    struct nk_vec2 spacing;\n\n    float item_offset = 0;\n    float item_width = 0;\n    float item_spacing = 0;\n    float panel_space = 0;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    style = &ctx->style;\n    NK_ASSERT(bounds);\n\n    spacing = style->window.spacing;\n    panel_space = nk_layout_row_calculate_usable_space(&ctx->style, layout->type,\n                                            layout->bounds.w, layout->row.columns);\n\n    #define NK_FRAC(x) (x - (float)(int)nk_roundf(x)) /* will be used to remove fookin gaps */\n    /* calculate the width of one item inside the current layout space */\n    switch (layout->row.type) {\n    case NK_LAYOUT_DYNAMIC_FIXED: {\n        /* scaling fixed size widgets item width */\n        float w = NK_MAX(1.0f,panel_space) / (float)layout->row.columns;\n        item_offset = (float)layout->row.index * w;\n        item_width = w + NK_FRAC(item_offset);\n        item_spacing = (float)layout->row.index * spacing.x;\n    } break;\n    case NK_LAYOUT_DYNAMIC_ROW: {\n        /* scaling single ratio widget width */\n        float w = layout->row.item_width * panel_space;\n        item_offset = layout->row.item_offset;\n        item_width = w + NK_FRAC(item_offset);\n        item_spacing = 0;\n\n        if (modify) {\n            layout->row.item_offset += w + spacing.x;\n            layout->row.filled += layout->row.item_width;\n            layout->row.index = 0;\n        }\n    } break;\n    case NK_LAYOUT_DYNAMIC_FREE: {\n        /* panel width depended free widget placing */\n        bounds->x = layout->at_x + (layout->bounds.w * layout->row.item.x);\n        bounds->x -= (float)*layout->offset_x;\n        bounds->y = layout->at_y + (layout->row.height * layout->row.item.y);\n        bounds->y -= (float)*layout->offset_y;\n        bounds->w = layout->bounds.w  * layout->row.item.w + NK_FRAC(bounds->x);\n        bounds->h = layout->row.height * layout->row.item.h + NK_FRAC(bounds->y);\n        return;\n    }\n    case NK_LAYOUT_DYNAMIC: {\n        /* scaling arrays of panel width ratios for every widget */\n        float ratio, w;\n        NK_ASSERT(layout->row.ratio);\n        ratio = (layout->row.ratio[layout->row.index] < 0) ?\n            layout->row.item_width : layout->row.ratio[layout->row.index];\n\n        w = (ratio * panel_space);\n        item_spacing = (float)layout->row.index * spacing.x;\n        item_offset = layout->row.item_offset;\n        item_width = w + NK_FRAC(item_offset);\n\n        if (modify) {\n            layout->row.item_offset += w;\n            layout->row.filled += ratio;\n        }\n    } break;\n    case NK_LAYOUT_STATIC_FIXED: {\n        /* non-scaling fixed widgets item width */\n        item_width = layout->row.item_width;\n        item_offset = (float)layout->row.index * item_width;\n        item_spacing = (float)layout->row.index * spacing.x;\n    } break;\n    case NK_LAYOUT_STATIC_ROW: {\n        /* scaling single ratio widget width */\n        item_width = layout->row.item_width;\n        item_offset = layout->row.item_offset;\n        item_spacing = (float)layout->row.index * spacing.x;\n        if (modify) layout->row.item_offset += item_width;\n    } break;\n    case NK_LAYOUT_STATIC_FREE: {\n        /* free widget placing */\n        bounds->x = layout->at_x + layout->row.item.x;\n        bounds->w = layout->row.item.w;\n        if (((bounds->x + bounds->w) > layout->max_x) && modify)\n            layout->max_x = (bounds->x + bounds->w);\n        bounds->x -= (float)*layout->offset_x;\n        bounds->y = layout->at_y + layout->row.item.y;\n        bounds->y -= (float)*layout->offset_y;\n        bounds->h = layout->row.item.h;\n        return;\n    }\n    case NK_LAYOUT_STATIC: {\n        /* non-scaling array of panel pixel width for every widget */\n        item_spacing = (float)layout->row.index * spacing.x;\n        item_width = layout->row.ratio[layout->row.index];\n        item_offset = layout->row.item_offset;\n        if (modify) layout->row.item_offset += item_width;\n    } break;\n    case NK_LAYOUT_TEMPLATE: {\n        /* stretchy row layout with combined dynamic/static widget width*/\n        float w;\n        NK_ASSERT(layout->row.index < layout->row.columns);\n        NK_ASSERT(layout->row.index < NK_MAX_LAYOUT_ROW_TEMPLATE_COLUMNS);\n        w = layout->row.templates[layout->row.index];\n        item_offset = layout->row.item_offset;\n        item_width = w + NK_FRAC(item_offset);\n        item_spacing = (float)layout->row.index * spacing.x;\n        if (modify) layout->row.item_offset += w;\n    } break;\n    #undef NK_FRAC\n    default: NK_ASSERT(0); break;\n    };\n\n    /* set the bounds of the newly allocated widget */\n    bounds->w = item_width;\n    bounds->h = layout->row.height - spacing.y;\n    bounds->y = layout->at_y - (float)*layout->offset_y;\n    bounds->x = layout->at_x + item_offset + item_spacing;\n    if (((bounds->x + bounds->w) > layout->max_x) && modify)\n        layout->max_x = bounds->x + bounds->w;\n    bounds->x -= (float)*layout->offset_x;\n}\nNK_LIB void\nnk_panel_alloc_space(struct nk_rect *bounds, const struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    /* check if the end of the row has been hit and begin new row if so */\n    win = ctx->current;\n    layout = win->layout;\n    if (layout->row.index >= layout->row.columns)\n        nk_panel_alloc_row(ctx, win);\n\n    /* calculate widget position and size */\n    nk_layout_widget_space(bounds, ctx, win, nk_true);\n    layout->row.index++;\n}\nNK_LIB void\nnk_layout_peek(struct nk_rect *bounds, const struct nk_context *ctx)\n{\n    float y;\n    int index;\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) {\n        *bounds = nk_rect(0,0,0,0);\n        return;\n    }\n\n    win = ctx->current;\n    layout = win->layout;\n    y = layout->at_y;\n    index = layout->row.index;\n    if (layout->row.index >= layout->row.columns) {\n        layout->at_y += layout->row.height;\n        layout->row.index = 0;\n    }\n    nk_layout_widget_space(bounds, ctx, win, nk_false);\n    if (!layout->row.index) {\n        bounds->x -= layout->row.item_offset;\n    }\n    layout->at_y = y;\n    layout->row.index = index;\n}\nNK_API void\nnk_spacer(struct nk_context *ctx )\n{\n    struct nk_rect dummy_rect = { 0, 0, 0, 0 };\n    nk_panel_alloc_space( &dummy_rect, ctx );\n}\n"
  },
  {
    "path": "src/nuklear_list_view.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                          LIST VIEW\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_list_view_begin(struct nk_context *ctx, struct nk_list_view *view,\n    const char *title, nk_flags flags, int row_height, int row_count)\n{\n    int title_len;\n    nk_hash title_hash;\n    nk_uint *x_offset;\n    nk_uint *y_offset;\n\n    int result;\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_style *style;\n    struct nk_vec2 item_spacing;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(view);\n    NK_ASSERT(title);\n    if (!ctx || !view || !title) return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    item_spacing = style->window.spacing;\n    row_height += NK_MAX(0, (int)item_spacing.y);\n\n    /* find persistent list view scrollbar offset */\n    title_len = (int)nk_strlen(title);\n    title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_GROUP);\n    x_offset = nk_find_value(win, title_hash);\n    if (!x_offset) {\n        x_offset = nk_add_value(ctx, win, title_hash, 0);\n        y_offset = nk_add_value(ctx, win, title_hash+1, 0);\n\n        NK_ASSERT(x_offset);\n        NK_ASSERT(y_offset);\n        if (!x_offset || !y_offset) return 0;\n        *x_offset = *y_offset = 0;\n    } else if (!(y_offset = nk_find_value(win, title_hash+1))) {\n        NK_ASSERT(y_offset);\n        if (!y_offset) return 0;\n        *x_offset = *y_offset = 0;\n    }\n    view->scroll_value = *y_offset;\n    view->scroll_pointer = y_offset;\n\n    *y_offset = 0;\n    result = nk_group_scrolled_offset_begin(ctx, x_offset, y_offset, title, flags);\n    win = ctx->current;\n    layout = win->layout;\n\n    view->total_height = row_height * NK_MAX(row_count,1);\n    view->begin = (int)NK_MAX(((float)view->scroll_value / (float)row_height), 0.0f);\n    view->count = (int)NK_MAX(nk_iceilf((layout->clip.h)/(float)row_height),0);\n    view->count = NK_MIN(view->count, row_count - view->begin);\n    view->end = view->begin + view->count;\n    view->ctx = ctx;\n    return result;\n}\nNK_API void\nnk_list_view_end(struct nk_list_view *view)\n{\n    struct nk_context *ctx;\n    struct nk_window *win;\n    struct nk_panel *layout;\n\n    NK_ASSERT(view);\n    NK_ASSERT(view->ctx);\n    NK_ASSERT(view->scroll_pointer);\n    if (!view || !view->ctx) return;\n\n    ctx = view->ctx;\n    win = ctx->current;\n    layout = win->layout;\n    layout->at_y = layout->bounds.y + (float)view->total_height;\n    *view->scroll_pointer = *view->scroll_pointer + view->scroll_value;\n    nk_group_end(view->ctx);\n}\n\n"
  },
  {
    "path": "src/nuklear_math.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              MATH\n *\n * ===============================================================*/\n/*/// ### Math\n///  Since nuklear is supposed to work on all systems providing floating point\n///  math without any dependencies I also had to implement my own math functions\n///  for sqrt, sin and cos. Since the actual highly accurate implementations for\n///  the standard library functions are quite complex and I do not need high\n///  precision for my use cases I use approximations.\n///\n///  Sqrt\n///  ----\n///  For square root nuklear uses the famous fast inverse square root:\n///  https://en.wikipedia.org/wiki/Fast_inverse_square_root with\n///  slightly tweaked magic constant. While on today's hardware it is\n///  probably not faster it is still fast and accurate enough for\n///  nuklear's use cases. IMPORTANT: this requires float format IEEE 754\n///\n///  Sine/Cosine\n///  -----------\n///  All constants inside both function are generated Remez's minimax\n///  approximations for value range 0...2*PI. The reason why I decided to\n///  approximate exactly that range is that nuklear only needs sine and\n///  cosine to generate circles which only requires that exact range.\n///  In addition I used Remez instead of Taylor for additional precision:\n///  www.lolengine.net/blog/2011/12/21/better-function-approximations.\n///\n///  The tool I used to generate constants for both sine and cosine\n///  (it can actually approximate a lot more functions) can be\n///  found here: www.lolengine.net/wiki/oss/lolremez\n*/\n#ifdef NK_INV_SQRT_NEEDED\nNK_LIB float\nnk_inv_sqrt(float n)\n{\n    float x2;\n    const float threehalfs = 1.5f;\n    union {nk_uint i; float f;} conv = {0};\n    conv.f = n;\n    x2 = n * 0.5f;\n    conv.i = 0x5f375A84 - (conv.i >> 1);\n    conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f));\n    return conv.f;\n}\n#endif\n#ifdef NK_SIN_NEEDED\nNK_LIB float\nnk_sin(float x)\n{\n    NK_STORAGE const float a0 = +1.91059300966915117e-31f;\n    NK_STORAGE const float a1 = +1.00086760103908896f;\n    NK_STORAGE const float a2 = -1.21276126894734565e-2f;\n    NK_STORAGE const float a3 = -1.38078780785773762e-1f;\n    NK_STORAGE const float a4 = -2.67353392911981221e-2f;\n    NK_STORAGE const float a5 = +2.08026600266304389e-2f;\n    NK_STORAGE const float a6 = -3.03996055049204407e-3f;\n    NK_STORAGE const float a7 = +1.38235642404333740e-4f;\n    return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*a7))))));\n}\n#endif\n#ifdef NK_COS_NEEDED\nNK_LIB float\nnk_cos(float x)\n{\n    /* New implementation. Also generated using lolremez. */\n    /* Old version significantly deviated from expected results. */\n    NK_STORAGE const float a0 = 9.9995999154986614e-1f;\n    NK_STORAGE const float a1 = 1.2548995793001028e-3f;\n    NK_STORAGE const float a2 = -5.0648546280678015e-1f;\n    NK_STORAGE const float a3 = 1.2942246466519995e-2f;\n    NK_STORAGE const float a4 = 2.8668384702547972e-2f;\n    NK_STORAGE const float a5 = 7.3726485210586547e-3f;\n    NK_STORAGE const float a6 = -3.8510875386947414e-3f;\n    NK_STORAGE const float a7 = 4.7196604604366623e-4f;\n    NK_STORAGE const float a8 = -1.8776444013090451e-5f;\n    return a0 + x*(a1 + x*(a2 + x*(a3 + x*(a4 + x*(a5 + x*(a6 + x*(a7 + x*a8)))))));\n}\n#endif\n#ifdef NK_ATAN_NEEDED\nNK_LIB float\nnk_atan(float x)\n{\n    /* ./lolremez --progress --float -d 9 -r \"0:pi*2\" \"atan(x)\" */\n    float u = -1.0989005e-05f;\n    NK_ASSERT(x >= 0.0f && \"TODO support negative floats\");\n    u = u * x + 0.00034117949f;\n    u = u * x + -0.0044932296f;\n    u = u * x + 0.032596264f;\n    u = u * x + -0.14088021f;\n    u = u * x + 0.36040401f;\n    u = u * x + -0.47017866f;\n    u = u * x + 0.00050198776f;\n    u = u * x + 1.0077682f;\n    u = u * x + -0.0004765437f;\n    return u;\n}\n#endif\n#ifdef NK_ATAN2_NEEDED\nNK_LIB float\nnk_atan2(float y, float x)\n{\n    float ax = NK_ABS(x),\n          ay = NK_ABS(y);\n    /* 0 = +y +x    1 = -y +x\n       2 = +y -x    3 = -y -x */\n    nk_uint signs = (y < 0) | ((x < 0) << 1);\n\n    float a;\n    if(y == 0.0 && x == 0.0) return 0.0f;\n    a = (ay > ax)\n        ? NK_PI_HALF - NK_ATAN(ax / ay)\n        : NK_ATAN(ay / ax);\n\n    switch(signs){\n        case 0: return a;\n        case 1: return -a;\n        case 2: return -a + NK_PI;\n        case 3: return a - NK_PI;\n    }\n    return 0.0f; /* prevents warning */\n}\n#endif\nNK_LIB nk_uint\nnk_round_up_pow2(nk_uint v)\n{\n    v--;\n    v |= v >> 1;\n    v |= v >> 2;\n    v |= v >> 4;\n    v |= v >> 8;\n    v |= v >> 16;\n    v++;\n    return v;\n}\n#ifdef NK_DTOA_NEEDED\nNK_LIB double\nnk_pow(double x, int n)\n{\n    /*  check the sign of n */\n    double r = 1;\n    int plus = n >= 0;\n    n = (plus) ? n : -n;\n    while (n > 0) {\n        if ((n & 1) == 1)\n            r *= x;\n        n /= 2;\n        x *= x;\n    }\n    return plus ? r : 1.0 / r;\n}\n#endif\n#ifdef NK_DTOA_NEEDED\nNK_LIB int\nnk_ifloord(double x)\n{\n    x = (double)((int)x - ((x < 0.0) ? 1 : 0));\n    return (int)x;\n}\n#endif\nNK_LIB int\nnk_ifloorf(float x)\n{\n    x = (float)((int)x - ((x < 0.0f) ? 1 : 0));\n    return (int)x;\n}\nNK_LIB int\nnk_iceilf(float x)\n{\n    if (x >= 0) {\n        int i = (int)x;\n        return (x > i) ? i+1: i;\n    } else {\n        int t = (int)x;\n        float r = x - (float)t;\n        return (r > 0.0f) ? t+1: t;\n    }\n}\n#ifdef NK_DTOA_NEEDED\nNK_LIB int\nnk_log10(double n)\n{\n    int neg;\n    int ret;\n    int exp = 0;\n\n    neg = (n < 0) ? 1 : 0;\n    ret = (neg) ? (int)-n : (int)n;\n    while ((ret / 10) > 0) {\n        ret /= 10;\n        exp++;\n    }\n    if (neg) exp = -exp;\n    return exp;\n}\n#endif\nNK_LIB float\nnk_roundf(float x)\n{\n    return (x >= 0.0f) ? (float)nk_ifloorf(x + 0.5f) : (float)nk_iceilf(x - 0.5f);\n}\nNK_API struct nk_rect\nnk_get_null_rect(void)\n{\n    return nk_null_rect;\n}\nNK_API struct nk_rect\nnk_rect(float x, float y, float w, float h)\n{\n    struct nk_rect r;\n    r.x = x; r.y = y;\n    r.w = w; r.h = h;\n    return r;\n}\nNK_API struct nk_rect\nnk_recti(int x, int y, int w, int h)\n{\n    struct nk_rect r;\n    r.x = (float)x;\n    r.y = (float)y;\n    r.w = (float)w;\n    r.h = (float)h;\n    return r;\n}\nNK_API struct nk_rect\nnk_recta(struct nk_vec2 pos, struct nk_vec2 size)\n{\n    return nk_rect(pos.x, pos.y, size.x, size.y);\n}\nNK_API struct nk_rect\nnk_rectv(const float *r)\n{\n    return nk_rect(r[0], r[1], r[2], r[3]);\n}\nNK_API struct nk_rect\nnk_rectiv(const int *r)\n{\n    return nk_recti(r[0], r[1], r[2], r[3]);\n}\nNK_API struct nk_vec2\nnk_rect_pos(struct nk_rect r)\n{\n    struct nk_vec2 ret;\n    ret.x = r.x; ret.y = r.y;\n    return ret;\n}\nNK_API struct nk_vec2\nnk_rect_size(struct nk_rect r)\n{\n    struct nk_vec2 ret;\n    ret.x = r.w; ret.y = r.h;\n    return ret;\n}\nNK_LIB struct nk_rect\nnk_shrink_rect(struct nk_rect r, float amount)\n{\n    struct nk_rect res;\n    r.w = NK_MAX(r.w, 2 * amount);\n    r.h = NK_MAX(r.h, 2 * amount);\n    res.x = r.x + amount;\n    res.y = r.y + amount;\n    res.w = r.w - 2 * amount;\n    res.h = r.h - 2 * amount;\n    return res;\n}\nNK_LIB struct nk_rect\nnk_pad_rect(struct nk_rect r, struct nk_vec2 pad)\n{\n    r.w = NK_MAX(r.w, 2 * pad.x);\n    r.h = NK_MAX(r.h, 2 * pad.y);\n    r.x += pad.x; r.y += pad.y;\n    r.w -= 2 * pad.x;\n    r.h -= 2 * pad.y;\n    return r;\n}\nNK_API struct nk_vec2\nnk_vec2(float x, float y)\n{\n    struct nk_vec2 ret;\n    ret.x = x; ret.y = y;\n    return ret;\n}\nNK_API struct nk_vec2\nnk_vec2i(int x, int y)\n{\n    struct nk_vec2 ret;\n    ret.x = (float)x;\n    ret.y = (float)y;\n    return ret;\n}\nNK_API struct nk_vec2\nnk_vec2v(const float *v)\n{\n    return nk_vec2(v[0], v[1]);\n}\nNK_API struct nk_vec2\nnk_vec2iv(const int *v)\n{\n    return nk_vec2i(v[0], v[1]);\n}\nNK_LIB void\nnk_unify(struct nk_rect *clip, const struct nk_rect *a, float x0, float y0,\n    float x1, float y1)\n{\n    NK_ASSERT(a);\n    NK_ASSERT(clip);\n    clip->x = NK_MAX(a->x, x0);\n    clip->y = NK_MAX(a->y, y0);\n    clip->w = NK_MIN(a->x + a->w, x1) - clip->x;\n    clip->h = NK_MIN(a->y + a->h, y1) - clip->y;\n    clip->w = NK_MAX(0, clip->w);\n    clip->h = NK_MAX(0, clip->h);\n}\n\nNK_API void\nnk_triangle_from_direction(struct nk_vec2 *result, struct nk_rect r,\n    float pad_x, float pad_y, enum nk_heading direction)\n{\n    float w_half, h_half;\n    NK_ASSERT(result);\n\n    r.w = NK_MAX(2 * pad_x, r.w);\n    r.h = NK_MAX(2 * pad_y, r.h);\n    r.w = r.w - 2 * pad_x;\n    r.h = r.h - 2 * pad_y;\n\n    r.x = r.x + pad_x;\n    r.y = r.y + pad_y;\n\n    w_half = r.w / 2.0f;\n    h_half = r.h / 2.0f;\n\n    if (direction == NK_UP) {\n        result[0] = nk_vec2(r.x + w_half, r.y);\n        result[1] = nk_vec2(r.x + r.w, r.y + r.h);\n        result[2] = nk_vec2(r.x, r.y + r.h);\n    } else if (direction == NK_RIGHT) {\n        result[0] = nk_vec2(r.x, r.y);\n        result[1] = nk_vec2(r.x + r.w, r.y + h_half);\n        result[2] = nk_vec2(r.x, r.y + r.h);\n    } else if (direction == NK_DOWN) {\n        result[0] = nk_vec2(r.x, r.y);\n        result[1] = nk_vec2(r.x + r.w, r.y);\n        result[2] = nk_vec2(r.x + w_half, r.y + r.h);\n    } else {\n        result[0] = nk_vec2(r.x, r.y + h_half);\n        result[1] = nk_vec2(r.x + r.w, r.y);\n        result[2] = nk_vec2(r.x + r.w, r.y + r.h);\n    }\n}\n\n"
  },
  {
    "path": "src/nuklear_menu.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              MENU\n *\n * ===============================================================*/\nNK_API void\nnk_menubar_begin(struct nk_context *ctx)\n{\n    struct nk_panel *layout;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    layout = ctx->current->layout;\n    NK_ASSERT(layout->at_y == layout->bounds.y);\n    /* if this assert triggers you allocated space between nk_begin and nk_menubar_begin.\n    If you want a menubar the first nuklear function after `nk_begin` has to be a\n    `nk_menubar_begin` call. Inside the menubar you then have to allocate space for\n    widgets (also supports multiple rows).\n    Example:\n        if (nk_begin(...)) {\n            nk_menubar_begin(...);\n                nk_layout_xxxx(...);\n                nk_button(...);\n                nk_layout_xxxx(...);\n                nk_button(...);\n            nk_menubar_end(...);\n        }\n        nk_end(...);\n    */\n    if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED)\n        return;\n\n    layout->menu.x = layout->at_x;\n    layout->menu.y = layout->at_y + layout->row.height;\n    layout->menu.w = layout->bounds.w;\n    layout->menu.offset.x = *layout->offset_x;\n    layout->menu.offset.y = *layout->offset_y;\n    *layout->offset_y = 0;\n}\nNK_API void\nnk_menubar_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    struct nk_command_buffer *out;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    out = &win->buffer;\n    layout = win->layout;\n    if (layout->flags & NK_WINDOW_HIDDEN || layout->flags & NK_WINDOW_MINIMIZED)\n        return;\n\n    layout->menu.h  = layout->at_y - layout->menu.y;\n    layout->menu.h += layout->row.height + ctx->style.window.spacing.y;\n\n    layout->bounds.y += layout->menu.h;\n    layout->bounds.h -= layout->menu.h;\n\n    *layout->offset_x = layout->menu.offset.x;\n    *layout->offset_y = layout->menu.offset.y;\n    layout->at_y      = layout->bounds.y - layout->row.height;\n\n    layout->clip.y = layout->bounds.y;\n    layout->clip.h = layout->bounds.h;\n    nk_push_scissor(out, layout->clip);\n}\nNK_INTERN int\nnk_menu_begin(struct nk_context *ctx, struct nk_window *win,\n    const char *id, int is_clicked, struct nk_rect header, struct nk_vec2 size)\n{\n    int is_open = 0;\n    int is_active = 0;\n    struct nk_rect body;\n    struct nk_window *popup;\n    nk_hash hash = nk_murmur_hash(id, (int)nk_strlen(id), NK_PANEL_MENU);\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    body.x = header.x;\n    body.w = size.x;\n    body.y = header.y + header.h;\n    body.h = size.y;\n\n    popup = win->popup.win;\n    is_open = popup ? nk_true : nk_false;\n    is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU);\n    if ((is_clicked && is_open && !is_active) || (is_open && !is_active) ||\n        (!is_open && !is_active && !is_clicked)) return 0;\n    if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU))\n        return 0;\n\n    win->popup.type = NK_PANEL_MENU;\n    win->popup.name = hash;\n    return 1;\n}\nNK_API nk_bool\nnk_menu_begin_text(struct nk_context *ctx, const char *title, int len,\n    nk_flags align, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    const struct nk_input *in;\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    nk_flags state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    state = nk_widget(&header, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, header,\n        title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font))\n        is_clicked = nk_true;\n    return nk_menu_begin(ctx, win, title, is_clicked, header, size);\n}\nNK_API nk_bool nk_menu_begin_label(struct nk_context *ctx,\n    const char *text, nk_flags align, struct nk_vec2 size)\n{\n    return nk_menu_begin_text(ctx, text, nk_strlen(text), align, size);\n}\nNK_API nk_bool\nnk_menu_begin_image(struct nk_context *ctx, const char *id, struct nk_image img,\n    struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_rect header;\n    const struct nk_input *in;\n    int is_clicked = nk_false;\n    nk_flags state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    state = nk_widget(&header, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_image(&ctx->last_widget_state, &win->buffer, header,\n        img, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in))\n        is_clicked = nk_true;\n    return nk_menu_begin(ctx, win, id, is_clicked, header, size);\n}\nNK_API nk_bool\nnk_menu_begin_symbol(struct nk_context *ctx, const char *id,\n    enum nk_symbol_type sym, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    const struct nk_input *in;\n    struct nk_rect header;\n    int is_clicked = nk_false;\n    nk_flags state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    state = nk_widget(&header, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_symbol(&ctx->last_widget_state,  &win->buffer, header,\n        sym, NK_BUTTON_DEFAULT, &ctx->style.menu_button, in, ctx->style.font))\n        is_clicked = nk_true;\n    return nk_menu_begin(ctx, win, id, is_clicked, header, size);\n}\nNK_API nk_bool\nnk_menu_begin_image_text(struct nk_context *ctx, const char *title, int len,\n    nk_flags align, struct nk_image img, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_rect header;\n    const struct nk_input *in;\n    int is_clicked = nk_false;\n    nk_flags state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    state = nk_widget(&header, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer,\n        header, img, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button,\n        ctx->style.font, in))\n        is_clicked = nk_true;\n    return nk_menu_begin(ctx, win, title, is_clicked, header, size);\n}\nNK_API nk_bool\nnk_menu_begin_image_label(struct nk_context *ctx,\n    const char *title, nk_flags align, struct nk_image img, struct nk_vec2 size)\n{\n    return nk_menu_begin_image_text(ctx, title, nk_strlen(title), align, img, size);\n}\nNK_API nk_bool\nnk_menu_begin_symbol_text(struct nk_context *ctx, const char *title, int len,\n    nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size)\n{\n    struct nk_window *win;\n    struct nk_rect header;\n    const struct nk_input *in;\n    int is_clicked = nk_false;\n    nk_flags state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    state = nk_widget(&header, ctx);\n    if (!state) return 0;\n\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer,\n        header, sym, title, len, align, NK_BUTTON_DEFAULT, &ctx->style.menu_button,\n        ctx->style.font, in)) is_clicked = nk_true;\n    return nk_menu_begin(ctx, win, title, is_clicked, header, size);\n}\nNK_API nk_bool\nnk_menu_begin_symbol_label(struct nk_context *ctx,\n    const char *title, nk_flags align, enum nk_symbol_type sym, struct nk_vec2 size )\n{\n    return nk_menu_begin_symbol_text(ctx, title, nk_strlen(title), align,sym,size);\n}\nNK_API nk_bool\nnk_menu_item_text(struct nk_context *ctx, const char *title, int len, nk_flags align)\n{\n    return nk_contextual_item_text(ctx, title, len, align);\n}\nNK_API nk_bool\nnk_menu_item_label(struct nk_context *ctx, const char *label, nk_flags align)\n{\n    return nk_contextual_item_label(ctx, label, align);\n}\nNK_API nk_bool\nnk_menu_item_image_label(struct nk_context *ctx, struct nk_image img,\n    const char *label, nk_flags align)\n{\n    return nk_contextual_item_image_label(ctx, img, label, align);\n}\nNK_API nk_bool\nnk_menu_item_image_text(struct nk_context *ctx, struct nk_image img,\n    const char *text, int len, nk_flags align)\n{\n    return nk_contextual_item_image_text(ctx, img, text, len, align);\n}\nNK_API nk_bool nk_menu_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *text, int len, nk_flags align)\n{\n    return nk_contextual_item_symbol_text(ctx, sym, text, len, align);\n}\nNK_API nk_bool nk_menu_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *label, nk_flags align)\n{\n    return nk_contextual_item_symbol_label(ctx, sym, label, align);\n}\nNK_API void nk_menu_close(struct nk_context *ctx)\n{\n    nk_contextual_close(ctx);\n}\nNK_API void\nnk_menu_end(struct nk_context *ctx)\n{\n    nk_contextual_end(ctx);\n}\n\n"
  },
  {
    "path": "src/nuklear_page_element.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                          PAGE ELEMENT\n *\n * ===============================================================*/\nNK_LIB struct nk_page_element*\nnk_create_page_element(struct nk_context *ctx)\n{\n    struct nk_page_element *elem;\n    if (ctx->freelist) {\n        /* unlink page element from free list */\n        elem = ctx->freelist;\n        ctx->freelist = elem->next;\n    } else if (ctx->use_pool) {\n        /* allocate page element from memory pool */\n        elem = nk_pool_alloc(&ctx->pool);\n        NK_ASSERT(elem);\n        if (!elem) return 0;\n    } else {\n        /* allocate new page element from back of fixed size memory buffer */\n        NK_STORAGE const nk_size size = sizeof(struct nk_page_element);\n        NK_STORAGE const nk_size align = NK_ALIGNOF(struct nk_page_element);\n        elem = (struct nk_page_element*)nk_buffer_alloc(&ctx->memory, NK_BUFFER_BACK, size, align);\n        NK_ASSERT(elem);\n        if (!elem) return 0;\n    }\n    nk_zero_struct(*elem);\n    elem->next = 0;\n    elem->prev = 0;\n    return elem;\n}\nNK_LIB void\nnk_link_page_element_into_freelist(struct nk_context *ctx,\n    struct nk_page_element *elem)\n{\n    /* link table into freelist */\n    if (!ctx->freelist) {\n        ctx->freelist = elem;\n    } else {\n        elem->next = ctx->freelist;\n        ctx->freelist = elem;\n    }\n}\nNK_LIB void\nnk_free_page_element(struct nk_context *ctx, struct nk_page_element *elem)\n{\n    /* we have a pool so just add to free list */\n    if (ctx->use_pool) {\n        nk_link_page_element_into_freelist(ctx, elem);\n        return;\n    }\n    /* if possible remove last element from back of fixed memory buffer */\n    {void *elem_end = (void*)(elem + 1);\n    void *buffer_end = (nk_byte*)ctx->memory.memory.ptr + ctx->memory.size;\n    if (elem_end == buffer_end)\n        ctx->memory.size -= sizeof(struct nk_page_element);\n    else nk_link_page_element_into_freelist(ctx, elem);}\n}\n\n"
  },
  {
    "path": "src/nuklear_panel.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              PANEL\n *\n * ===============================================================*/\nNK_LIB void*\nnk_create_panel(struct nk_context *ctx)\n{\n    struct nk_page_element *elem;\n    elem = nk_create_page_element(ctx);\n    if (!elem) return 0;\n    return &elem->data.pan;\n}\nNK_LIB void\nnk_free_panel(struct nk_context *ctx, struct nk_panel *pan)\n{\n    union nk_page_data *pd = NK_CONTAINER_OF(pan, union nk_page_data, pan);\n    struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);\n    nk_free_page_element(ctx, pe);\n}\nNK_LIB nk_bool\nnk_panel_has_header(nk_flags flags, const char *title)\n{\n    nk_bool active = 0;\n    active = (flags & (NK_WINDOW_CLOSABLE|NK_WINDOW_MINIMIZABLE));\n    active = active || (flags & NK_WINDOW_TITLE);\n    active = active && !(flags & NK_WINDOW_HIDDEN) && title;\n    return active;\n}\nNK_LIB struct nk_vec2\nnk_panel_get_padding(const struct nk_style *style, enum nk_panel_type type)\n{\n    switch (type) {\n    default:\n    case NK_PANEL_WINDOW: return style->window.padding;\n    case NK_PANEL_GROUP: return style->window.group_padding;\n    case NK_PANEL_POPUP: return style->window.popup_padding;\n    case NK_PANEL_CONTEXTUAL: return style->window.contextual_padding;\n    case NK_PANEL_COMBO: return style->window.combo_padding;\n    case NK_PANEL_MENU: return style->window.menu_padding;\n    case NK_PANEL_TOOLTIP: return style->window.menu_padding;}\n}\nNK_LIB float\nnk_panel_get_border(const struct nk_style *style, nk_flags flags,\n    enum nk_panel_type type)\n{\n    if (flags & NK_WINDOW_BORDER) {\n        switch (type) {\n        default:\n        case NK_PANEL_WINDOW: return style->window.border;\n        case NK_PANEL_GROUP: return style->window.group_border;\n        case NK_PANEL_POPUP: return style->window.popup_border;\n        case NK_PANEL_CONTEXTUAL: return style->window.contextual_border;\n        case NK_PANEL_COMBO: return style->window.combo_border;\n        case NK_PANEL_MENU: return style->window.menu_border;\n        case NK_PANEL_TOOLTIP: return style->window.menu_border;\n    }} else return 0;\n}\nNK_LIB struct nk_color\nnk_panel_get_border_color(const struct nk_style *style, enum nk_panel_type type)\n{\n    switch (type) {\n    default:\n    case NK_PANEL_WINDOW: return style->window.border_color;\n    case NK_PANEL_GROUP: return style->window.group_border_color;\n    case NK_PANEL_POPUP: return style->window.popup_border_color;\n    case NK_PANEL_CONTEXTUAL: return style->window.contextual_border_color;\n    case NK_PANEL_COMBO: return style->window.combo_border_color;\n    case NK_PANEL_MENU: return style->window.menu_border_color;\n    case NK_PANEL_TOOLTIP: return style->window.menu_border_color;}\n}\nNK_LIB nk_bool\nnk_panel_is_sub(enum nk_panel_type type)\n{\n    return ((int)type & (int)NK_PANEL_SET_SUB)?1:0;\n}\nNK_LIB nk_bool\nnk_panel_is_nonblock(enum nk_panel_type type)\n{\n    return ((int)type & (int)NK_PANEL_SET_NONBLOCK)?1:0;\n}\nNK_LIB nk_bool\nnk_panel_begin(struct nk_context *ctx, const char *title, enum nk_panel_type panel_type)\n{\n    struct nk_input *in;\n    struct nk_window *win;\n    struct nk_panel *layout;\n    struct nk_command_buffer *out;\n    const struct nk_style *style;\n    const struct nk_user_font *font;\n\n    struct nk_vec2 scrollbar_size;\n    struct nk_vec2 panel_padding;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) return 0;\n    nk_zero(ctx->current->layout, sizeof(*ctx->current->layout));\n    if ((ctx->current->flags & NK_WINDOW_HIDDEN) || (ctx->current->flags & NK_WINDOW_CLOSED)) {\n        nk_zero(ctx->current->layout, sizeof(struct nk_panel));\n        ctx->current->layout->type = panel_type;\n        return 0;\n    }\n    /* pull state into local stack */\n    style = &ctx->style;\n    font = style->font;\n    win = ctx->current;\n    layout = win->layout;\n    out = &win->buffer;\n    in = (win->flags & NK_WINDOW_NO_INPUT) ? 0: &ctx->input;\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    win->buffer.userdata = ctx->userdata;\n#endif\n    /* pull style configuration into local stack */\n    scrollbar_size = style->window.scrollbar_size;\n    panel_padding = nk_panel_get_padding(style, panel_type);\n\n    /* window movement */\n    if ((win->flags & NK_WINDOW_MOVABLE) && !(win->flags & NK_WINDOW_ROM)) {\n        nk_bool left_mouse_down;\n        unsigned int left_mouse_clicked;\n        int left_mouse_click_in_cursor;\n\n        /* calculate draggable window space */\n        struct nk_rect header;\n        header.x = win->bounds.x;\n        header.y = win->bounds.y;\n        header.w = win->bounds.w;\n        if (nk_panel_has_header(win->flags, title)) {\n            header.h = font->height + 2.0f * style->window.header.padding.y;\n            header.h += 2.0f * style->window.header.label_padding.y;\n        } else header.h = panel_padding.y;\n\n        /* window movement by dragging */\n        left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;\n        left_mouse_clicked = in->mouse.buttons[NK_BUTTON_LEFT].clicked;\n        left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,\n            NK_BUTTON_LEFT, header, nk_true);\n        if (left_mouse_down && left_mouse_click_in_cursor && !left_mouse_clicked) {\n            win->bounds.x = win->bounds.x + in->mouse.delta.x;\n            win->bounds.y = win->bounds.y + in->mouse.delta.y;\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x += in->mouse.delta.x;\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y += in->mouse.delta.y;\n            ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_MOVE];\n        }\n    }\n\n    /* setup panel */\n    layout->type = panel_type;\n    layout->flags = win->flags;\n    layout->bounds = win->bounds;\n    layout->bounds.x += panel_padding.x;\n    layout->bounds.w -= 2*panel_padding.x;\n    if (win->flags & NK_WINDOW_BORDER) {\n        layout->border = nk_panel_get_border(style, win->flags, panel_type);\n        layout->bounds = nk_shrink_rect(layout->bounds, layout->border);\n    } else layout->border = 0;\n    layout->at_y = layout->bounds.y;\n    layout->at_x = layout->bounds.x;\n    layout->max_x = 0;\n    layout->header_height = 0;\n    layout->footer_height = 0;\n    nk_layout_reset_min_row_height(ctx);\n    layout->row.index = 0;\n    layout->row.columns = 0;\n    layout->row.ratio = 0;\n    layout->row.item_width = 0;\n    layout->row.tree_depth = 0;\n    layout->row.height = panel_padding.y;\n    layout->has_scrolling = nk_true;\n    if (!(win->flags & NK_WINDOW_NO_SCROLLBAR))\n        layout->bounds.w -= scrollbar_size.x;\n    if (!nk_panel_is_nonblock(panel_type)) {\n        layout->footer_height = 0;\n        if (!(win->flags & NK_WINDOW_NO_SCROLLBAR) || win->flags & NK_WINDOW_SCALABLE)\n            layout->footer_height = scrollbar_size.y;\n        layout->bounds.h -= layout->footer_height;\n    }\n\n    /* panel header */\n    if (nk_panel_has_header(win->flags, title))\n    {\n        struct nk_text text;\n        struct nk_rect header;\n        const struct nk_style_item *background = 0;\n\n        /* calculate header bounds */\n        header.x = win->bounds.x;\n        header.y = win->bounds.y;\n        header.w = win->bounds.w;\n        header.h = font->height + 2.0f * style->window.header.padding.y;\n        header.h += (2.0f * style->window.header.label_padding.y);\n\n        /* shrink panel by header */\n        layout->header_height = header.h;\n        layout->bounds.y += header.h;\n        layout->bounds.h -= header.h;\n        layout->at_y += header.h;\n\n        /* select correct header background and text color */\n        if (ctx->active == win) {\n            background = &style->window.header.active;\n            text.text = style->window.header.label_active;\n        } else if (nk_input_is_mouse_hovering_rect(&ctx->input, header)) {\n            background = &style->window.header.hover;\n            text.text = style->window.header.label_hover;\n        } else {\n            background = &style->window.header.normal;\n            text.text = style->window.header.label_normal;\n        }\n\n        /* draw header background */\n        header.h += 1.0f;\n\n        switch(background->type) {\n            case NK_STYLE_ITEM_IMAGE:\n                text.background = nk_rgba(0,0,0,0);\n                nk_draw_image(&win->buffer, header, &background->data.image, nk_white);\n                break;\n            case NK_STYLE_ITEM_NINE_SLICE:\n                text.background = nk_rgba(0, 0, 0, 0);\n                nk_draw_nine_slice(&win->buffer, header, &background->data.slice, nk_white);\n                break;\n            case NK_STYLE_ITEM_COLOR:\n                text.background = background->data.color;\n                nk_fill_rect(out, header, 0, background->data.color);\n                break;\n        }\n\n        /* window close button */\n        {struct nk_rect button;\n        button.y = header.y + style->window.header.padding.y;\n        button.h = header.h - 2 * style->window.header.padding.y;\n        button.w = button.h;\n        if (win->flags & NK_WINDOW_CLOSABLE) {\n            nk_flags ws = 0;\n            if (style->window.header.align == NK_HEADER_RIGHT) {\n                button.x = (header.w + header.x) - (button.w + style->window.header.padding.x);\n                header.w -= button.w + style->window.header.spacing.x + style->window.header.padding.x;\n            } else {\n                button.x = header.x + style->window.header.padding.x;\n                header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x;\n            }\n\n            if (nk_do_button_symbol(&ws, &win->buffer, button,\n                style->window.header.close_symbol, NK_BUTTON_DEFAULT,\n                &style->window.header.close_button, in, style->font) && !(win->flags & NK_WINDOW_ROM))\n            {\n                layout->flags |= NK_WINDOW_HIDDEN;\n                layout->flags &= (nk_flags)~NK_WINDOW_MINIMIZED;\n            }\n        }\n\n        /* window minimize button */\n        if (win->flags & NK_WINDOW_MINIMIZABLE) {\n            nk_flags ws = 0;\n            if (style->window.header.align == NK_HEADER_RIGHT) {\n                button.x = (header.w + header.x) - button.w;\n                if (!(win->flags & NK_WINDOW_CLOSABLE)) {\n                    button.x -= style->window.header.padding.x;\n                    header.w -= style->window.header.padding.x;\n                }\n                header.w -= button.w + style->window.header.spacing.x;\n            } else {\n                button.x = header.x;\n                header.x += button.w + style->window.header.spacing.x + style->window.header.padding.x;\n            }\n            if (nk_do_button_symbol(&ws, &win->buffer, button, (layout->flags & NK_WINDOW_MINIMIZED)?\n                style->window.header.maximize_symbol: style->window.header.minimize_symbol,\n                NK_BUTTON_DEFAULT, &style->window.header.minimize_button, in, style->font) && !(win->flags & NK_WINDOW_ROM))\n                layout->flags = (layout->flags & NK_WINDOW_MINIMIZED) ?\n                    layout->flags & (nk_flags)~NK_WINDOW_MINIMIZED:\n                    layout->flags | NK_WINDOW_MINIMIZED;\n        }}\n\n        {/* window header title */\n        int text_len = nk_strlen(title);\n        struct nk_rect label = {0,0,0,0};\n        float t = font->width(font->userdata, font->height, title, text_len);\n        text.padding = nk_vec2(0,0);\n\n        label.x = header.x + style->window.header.padding.x;\n        label.x += style->window.header.label_padding.x;\n        label.y = header.y + style->window.header.label_padding.y;\n        label.h = font->height + 2 * style->window.header.label_padding.y;\n        label.w = t + 2 * style->window.header.spacing.x;\n        label.w = NK_CLAMP(0, label.w, header.x + header.w - label.x);\n        nk_widget_text(out, label, (const char*)title, text_len, &text, NK_TEXT_LEFT, font);}\n    }\n\n    /* draw window background */\n    if (!(layout->flags & NK_WINDOW_MINIMIZED) && !(layout->flags & NK_WINDOW_DYNAMIC)) {\n        struct nk_rect body;\n        body.x = win->bounds.x;\n        body.w = win->bounds.w;\n        body.y = (win->bounds.y + layout->header_height);\n        body.h = (win->bounds.h - layout->header_height);\n\n        switch(style->window.fixed_background.type) {\n            case NK_STYLE_ITEM_IMAGE:\n                nk_draw_image(out, body, &style->window.fixed_background.data.image, nk_white);\n                break;\n            case NK_STYLE_ITEM_NINE_SLICE:\n                nk_draw_nine_slice(out, body, &style->window.fixed_background.data.slice, nk_white);\n                break;\n            case NK_STYLE_ITEM_COLOR:\n                nk_fill_rect(out, body, style->window.rounding, style->window.fixed_background.data.color);\n                break;\n        }\n    }\n\n    /* set clipping rectangle */\n    {struct nk_rect clip;\n    layout->clip = layout->bounds;\n    nk_unify(&clip, &win->buffer.clip, layout->clip.x, layout->clip.y,\n        layout->clip.x + layout->clip.w, layout->clip.y + layout->clip.h);\n    nk_push_scissor(out, clip);\n    layout->clip = clip;}\n    return !(layout->flags & NK_WINDOW_HIDDEN) && !(layout->flags & NK_WINDOW_MINIMIZED);\n}\nNK_LIB void\nnk_panel_end(struct nk_context *ctx)\n{\n    struct nk_input *in;\n    struct nk_window *window;\n    struct nk_panel *layout;\n    const struct nk_style *style;\n    struct nk_command_buffer *out;\n\n    struct nk_vec2 scrollbar_size;\n    struct nk_vec2 panel_padding;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    window = ctx->current;\n    layout = window->layout;\n    style = &ctx->style;\n    out = &window->buffer;\n    in = (layout->flags & NK_WINDOW_ROM || layout->flags & NK_WINDOW_NO_INPUT) ? 0 :&ctx->input;\n    if (!nk_panel_is_sub(layout->type))\n        nk_push_scissor(out, nk_null_rect);\n\n    /* cache configuration data */\n    scrollbar_size = style->window.scrollbar_size;\n    panel_padding = nk_panel_get_padding(style, layout->type);\n\n    /* update the current cursor Y-position to point over the last added widget */\n    layout->at_y += layout->row.height;\n\n    /* dynamic panels */\n    if (layout->flags & NK_WINDOW_DYNAMIC && !(layout->flags & NK_WINDOW_MINIMIZED))\n    {\n        /* update panel height to fit dynamic growth */\n        struct nk_rect empty_space;\n        if (layout->at_y < (layout->bounds.y + layout->bounds.h))\n            layout->bounds.h = layout->at_y - layout->bounds.y;\n\n        /* fill top empty space */\n        empty_space.x = window->bounds.x;\n        empty_space.y = layout->bounds.y;\n        empty_space.h = panel_padding.y;\n        empty_space.w = window->bounds.w;\n        nk_fill_rect(out, empty_space, 0, style->window.background);\n\n        /* fill left empty space */\n        empty_space.x = window->bounds.x;\n        empty_space.y = layout->bounds.y;\n        empty_space.w = panel_padding.x + layout->border;\n        empty_space.h = layout->bounds.h;\n        nk_fill_rect(out, empty_space, 0, style->window.background);\n\n        /* fill right empty space */\n        empty_space.x = layout->bounds.x + layout->bounds.w;\n        empty_space.y = layout->bounds.y;\n        empty_space.w = panel_padding.x + layout->border;\n        empty_space.h = layout->bounds.h;\n        if (*layout->offset_y == 0 && !(layout->flags & NK_WINDOW_NO_SCROLLBAR))\n            empty_space.w += scrollbar_size.x;\n        nk_fill_rect(out, empty_space, 0, style->window.background);\n\n        /* fill bottom empty space */\n        if (layout->footer_height > 0) {\n            empty_space.x = window->bounds.x;\n            empty_space.y = layout->bounds.y + layout->bounds.h;\n            empty_space.w = window->bounds.w;\n            empty_space.h = layout->footer_height;\n            nk_fill_rect(out, empty_space, 0, style->window.background);\n        }\n    }\n\n    /* scrollbars */\n    if (!(layout->flags & NK_WINDOW_NO_SCROLLBAR) &&\n        !(layout->flags & NK_WINDOW_MINIMIZED) &&\n        window->scrollbar_hiding_timer < NK_SCROLLBAR_HIDING_TIMEOUT)\n    {\n        struct nk_rect scroll;\n        int scroll_has_scrolling;\n        float scroll_target;\n        float scroll_offset;\n        float scroll_step;\n        float scroll_inc;\n\n        /* mouse wheel scrolling */\n        if (nk_panel_is_sub(layout->type))\n        {\n            /* sub-window mouse wheel scrolling */\n            struct nk_window *root_window = window;\n            struct nk_panel *root_panel = window->layout;\n            while (root_panel->parent)\n                root_panel = root_panel->parent;\n            while (root_window->parent)\n                root_window = root_window->parent;\n\n            /* only allow scrolling if parent window is active */\n            scroll_has_scrolling = nk_false;\n            if ((root_window == ctx->active) && layout->has_scrolling) {\n                /* and panel is being hovered and inside clip rect*/\n                if (nk_input_is_mouse_hovering_rect(in, layout->bounds) &&\n                    NK_INTERSECT(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->bounds.h,\n                        root_panel->clip.x, root_panel->clip.y, root_panel->clip.w, root_panel->clip.h))\n                {\n                    /* deactivate all parent scrolling */\n                    root_panel = window->layout;\n                    while (root_panel->parent) {\n                        root_panel->has_scrolling = nk_false;\n                        root_panel = root_panel->parent;\n                    }\n                    root_panel->has_scrolling = nk_false;\n                    scroll_has_scrolling = nk_true;\n                }\n            }\n        } else {\n            /* window mouse wheel scrolling */\n            scroll_has_scrolling = (window == ctx->active) && layout->has_scrolling;\n            if (in && (in->mouse.scroll_delta.y > 0 || in->mouse.scroll_delta.x > 0) && scroll_has_scrolling)\n                window->scrolled = nk_true;\n            else window->scrolled = nk_false;\n        }\n\n        {\n            /* vertical scrollbar */\n            nk_flags state = 0;\n            scroll.x = layout->bounds.x + layout->bounds.w + panel_padding.x;\n            scroll.y = layout->bounds.y;\n            scroll.w = scrollbar_size.x;\n            scroll.h = layout->bounds.h;\n\n            scroll_offset = (float)*layout->offset_y;\n            scroll_step = scroll.h * 0.10f;\n            scroll_inc = scroll.h * 0.01f;\n            scroll_target = (float)(int)(layout->at_y - scroll.y);\n            scroll_offset = nk_do_scrollbarv(&state, out, scroll, scroll_has_scrolling,\n                scroll_offset, scroll_target, scroll_step, scroll_inc,\n                &ctx->style.scrollv, in, style->font);\n            *layout->offset_y = (nk_uint)scroll_offset;\n            if (in && scroll_has_scrolling)\n                in->mouse.scroll_delta.y = 0;\n        }\n        {\n            /* horizontal scrollbar */\n            nk_flags state = 0;\n            scroll.x = layout->bounds.x;\n            scroll.y = layout->bounds.y + layout->bounds.h;\n            scroll.w = layout->bounds.w;\n            scroll.h = scrollbar_size.y;\n\n            scroll_offset = (float)*layout->offset_x;\n            scroll_target = (float)(int)(layout->max_x - scroll.x);\n            scroll_step = layout->max_x * 0.05f;\n            scroll_inc = layout->max_x * 0.005f;\n            scroll_offset = nk_do_scrollbarh(&state, out, scroll, scroll_has_scrolling,\n                scroll_offset, scroll_target, scroll_step, scroll_inc,\n                &ctx->style.scrollh, in, style->font);\n            *layout->offset_x = (nk_uint)scroll_offset;\n        }\n    }\n\n    /* hide scroll if no user input */\n    if (window->flags & NK_WINDOW_SCROLL_AUTO_HIDE) {\n        int has_input = nk_input_is_mouse_moved(&ctx->input) || ctx->input.mouse.scroll_delta.y != 0;\n        int is_window_hovered = nk_window_is_hovered(ctx);\n        int any_item_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);\n        if ((!has_input && is_window_hovered) || (!is_window_hovered && !any_item_active))\n            window->scrollbar_hiding_timer += ctx->delta_time_seconds;\n        else window->scrollbar_hiding_timer = 0;\n    } else window->scrollbar_hiding_timer = 0;\n\n    /* window border */\n    if (layout->flags & NK_WINDOW_BORDER)\n    {\n        struct nk_color border_color = nk_panel_get_border_color(style, layout->type);\n        const float padding_y = (layout->flags & NK_WINDOW_MINIMIZED)\n            ? (style->window.border + window->bounds.y + layout->header_height)\n            : ((layout->flags & NK_WINDOW_DYNAMIC)\n                ? (layout->bounds.y + layout->bounds.h + layout->footer_height)\n                : (window->bounds.y + window->bounds.h));\n        struct nk_rect b = window->bounds;\n        b.h = padding_y - window->bounds.y;\n        nk_stroke_rect(out, b, style->window.rounding, layout->border, border_color);\n    }\n\n    /* scaler */\n    if ((layout->flags & NK_WINDOW_SCALABLE) && in && !(layout->flags & NK_WINDOW_MINIMIZED))\n    {\n        /* calculate scaler bounds */\n        struct nk_rect scaler;\n        scaler.w = scrollbar_size.x;\n        scaler.h = scrollbar_size.y;\n        scaler.y = layout->bounds.y + layout->bounds.h;\n        if (layout->flags & NK_WINDOW_SCALE_LEFT)\n            scaler.x = layout->bounds.x - panel_padding.x * 0.5f;\n        else scaler.x = layout->bounds.x + layout->bounds.w + panel_padding.x;\n        if (layout->flags & NK_WINDOW_NO_SCROLLBAR)\n            scaler.x -= scaler.w;\n\n        /* draw scaler */\n        {const struct nk_style_item *item = &style->window.scaler;\n        if (item->type == NK_STYLE_ITEM_IMAGE)\n            nk_draw_image(out, scaler, &item->data.image, nk_white);\n        else {\n            if (layout->flags & NK_WINDOW_SCALE_LEFT) {\n                nk_fill_triangle(out, scaler.x, scaler.y, scaler.x,\n                    scaler.y + scaler.h, scaler.x + scaler.w,\n                    scaler.y + scaler.h, item->data.color);\n            } else {\n                nk_fill_triangle(out, scaler.x + scaler.w, scaler.y, scaler.x + scaler.w,\n                    scaler.y + scaler.h, scaler.x, scaler.y + scaler.h, item->data.color);\n            }\n        }}\n\n        /* do window scaling */\n        if (!(window->flags & NK_WINDOW_ROM)) {\n            struct nk_vec2 window_size = style->window.min_size;\n            int left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;\n            int left_mouse_click_in_scaler = nk_input_has_mouse_click_down_in_rect(in,\n                    NK_BUTTON_LEFT, scaler, nk_true);\n\n            if (left_mouse_down && left_mouse_click_in_scaler) {\n                float delta_x = in->mouse.delta.x;\n                if (layout->flags & NK_WINDOW_SCALE_LEFT) {\n                    delta_x = -delta_x;\n                    window->bounds.x += in->mouse.delta.x;\n                }\n                /* dragging in x-direction  */\n                if (window->bounds.w + delta_x >= window_size.x) {\n                    if ((delta_x < 0) || (delta_x > 0 && in->mouse.pos.x >= scaler.x)) {\n                        window->bounds.w = window->bounds.w + delta_x;\n                        scaler.x += in->mouse.delta.x;\n                    }\n                }\n                /* dragging in y-direction (only possible if static window) */\n                if (!(layout->flags & NK_WINDOW_DYNAMIC)) {\n                    if (window_size.y < window->bounds.h + in->mouse.delta.y) {\n                        if ((in->mouse.delta.y < 0) || (in->mouse.delta.y > 0 && in->mouse.pos.y >= scaler.y)) {\n                            window->bounds.h = window->bounds.h + in->mouse.delta.y;\n                            scaler.y += in->mouse.delta.y;\n                        }\n                    }\n                }\n                ctx->style.cursor_active = ctx->style.cursors[NK_CURSOR_RESIZE_TOP_RIGHT_DOWN_LEFT];\n                in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = scaler.x + scaler.w/2.0f;\n                in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = scaler.y + scaler.h/2.0f;\n            }\n        }\n    }\n    if (!nk_panel_is_sub(layout->type)) {\n        /* window is hidden so clear command buffer  */\n        if (layout->flags & NK_WINDOW_HIDDEN)\n            nk_command_buffer_reset(&window->buffer);\n        /* window is visible and not tab */\n        else nk_finish(ctx, window);\n    }\n\n    /* NK_WINDOW_REMOVE_ROM flag was set so remove NK_WINDOW_ROM */\n    if (layout->flags & NK_WINDOW_REMOVE_ROM) {\n        layout->flags &= ~(nk_flags)NK_WINDOW_ROM;\n        layout->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM;\n    }\n    window->flags = layout->flags;\n\n    /* property garbage collector */\n    if (window->property.active && window->property.old != window->property.seq &&\n        window->property.active == window->property.prev) {\n        nk_zero(&window->property, sizeof(window->property));\n    } else {\n        window->property.old = window->property.seq;\n        window->property.prev = window->property.active;\n        window->property.seq = 0;\n    }\n    /* edit garbage collector */\n    if (window->edit.active && window->edit.old != window->edit.seq &&\n       window->edit.active == window->edit.prev) {\n        nk_zero(&window->edit, sizeof(window->edit));\n    } else {\n        window->edit.old = window->edit.seq;\n        window->edit.prev = window->edit.active;\n        window->edit.seq = 0;\n    }\n    /* contextual garbage collector */\n    if (window->popup.active_con && window->popup.con_old != window->popup.con_count) {\n        window->popup.con_count = 0;\n        window->popup.con_old = 0;\n        window->popup.active_con = 0;\n    } else {\n        window->popup.con_old = window->popup.con_count;\n        window->popup.con_count = 0;\n    }\n    window->popup.combo_count = 0;\n    /* helper to make sure you have a 'nk_tree_push' for every 'nk_tree_pop' */\n    NK_ASSERT(!layout->row.tree_depth);\n}\n\n"
  },
  {
    "path": "src/nuklear_pool.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              POOL\n *\n * ===============================================================*/\nNK_LIB void\nnk_pool_init(struct nk_pool *pool, const struct nk_allocator *alloc,\n    unsigned int capacity)\n{\n    NK_ASSERT(capacity >= 1);\n    nk_zero(pool, sizeof(*pool));\n    pool->alloc = *alloc;\n    pool->capacity = capacity;\n    pool->type = NK_BUFFER_DYNAMIC;\n    pool->pages = 0;\n}\nNK_LIB void\nnk_pool_free(struct nk_pool *pool)\n{\n    struct nk_page *iter;\n    if (!pool) return;\n    iter = pool->pages;\n    if (pool->type == NK_BUFFER_FIXED) return;\n    while (iter) {\n        struct nk_page *next = iter->next;\n        pool->alloc.free(pool->alloc.userdata, iter);\n        iter = next;\n    }\n}\nNK_LIB void\nnk_pool_init_fixed(struct nk_pool *pool, void *memory, nk_size size)\n{\n    nk_zero(pool, sizeof(*pool));\n    NK_ASSERT(size >= sizeof(struct nk_page));\n    if (size < sizeof(struct nk_page)) return;\n    /* first nk_page_element is embedded in nk_page, additional elements follow in adjacent space */\n    pool->capacity = (unsigned)(1 + (size - sizeof(struct nk_page)) / sizeof(struct nk_page_element));\n    pool->pages = (struct nk_page*)memory;\n    pool->type = NK_BUFFER_FIXED;\n    pool->size = size;\n}\nNK_LIB struct nk_page_element*\nnk_pool_alloc(struct nk_pool *pool)\n{\n    if (!pool->pages || pool->pages->size >= pool->capacity) {\n        /* allocate new page */\n        struct nk_page *page;\n        if (pool->type == NK_BUFFER_FIXED) {\n            NK_ASSERT(pool->pages);\n            if (!pool->pages) return 0;\n            NK_ASSERT(pool->pages->size < pool->capacity);\n            return 0;\n        } else {\n            nk_size size = sizeof(struct nk_page);\n            size += (pool->capacity - 1) * sizeof(struct nk_page_element);\n            page = (struct nk_page*)pool->alloc.alloc(pool->alloc.userdata,0, size);\n            page->next = pool->pages;\n            pool->pages = page;\n            page->size = 0;\n        }\n    } return &pool->pages->win[pool->pages->size++];\n}\n\n"
  },
  {
    "path": "src/nuklear_popup.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              POPUP\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_popup_begin(struct nk_context *ctx, enum nk_popup_type type,\n    const char *title, nk_flags flags, struct nk_rect rect)\n{\n    struct nk_window *popup;\n    struct nk_window *win;\n    struct nk_panel *panel;\n\n    int title_len;\n    nk_hash title_hash;\n    nk_size allocated;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(title);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    win = ctx->current;\n    panel = win->layout;\n    NK_ASSERT(!((int)panel->type & (int)NK_PANEL_SET_POPUP) && \"popups are not allowed to have popups\");\n    (void)panel;\n    title_len = (int)nk_strlen(title);\n    title_hash = nk_murmur_hash(title, (int)title_len, NK_PANEL_POPUP);\n\n    popup = win->popup.win;\n    if (!popup) {\n        popup = (struct nk_window*)nk_create_window(ctx);\n        popup->parent = win;\n        win->popup.win = popup;\n        win->popup.active = 0;\n        win->popup.type = NK_PANEL_POPUP;\n    }\n\n    /* make sure we have correct popup */\n    if (win->popup.name != title_hash) {\n        if (!win->popup.active) {\n            nk_zero(popup, sizeof(*popup));\n            win->popup.name = title_hash;\n            win->popup.active = 1;\n            win->popup.type = NK_PANEL_POPUP;\n        } else return 0;\n    }\n\n    /* popup position is local to window */\n    ctx->current = popup;\n    rect.x += win->layout->clip.x;\n    rect.y += win->layout->clip.y;\n\n    /* setup popup data */\n    popup->parent = win;\n    popup->bounds = rect;\n    popup->seq = ctx->seq;\n    popup->layout = (struct nk_panel*)nk_create_panel(ctx);\n    popup->flags = flags;\n    popup->flags |= NK_WINDOW_BORDER;\n    if (type == NK_POPUP_DYNAMIC)\n        popup->flags |= NK_WINDOW_DYNAMIC;\n\n    popup->buffer = win->buffer;\n    nk_start_popup(ctx, win);\n    allocated = ctx->memory.allocated;\n    nk_push_scissor(&popup->buffer, nk_null_rect);\n\n    if (nk_panel_begin(ctx, title, NK_PANEL_POPUP)) {\n        /* popup is running therefore invalidate parent panels */\n        struct nk_panel *root;\n        root = win->layout;\n        while (root) {\n            root->flags |= NK_WINDOW_ROM;\n            root->flags &= ~(nk_flags)NK_WINDOW_REMOVE_ROM;\n            root = root->parent;\n        }\n        win->popup.active = 1;\n        popup->layout->offset_x = &popup->scrollbar.x;\n        popup->layout->offset_y = &popup->scrollbar.y;\n        popup->layout->parent = win->layout;\n        return 1;\n    } else {\n        /* popup was closed/is invalid so cleanup */\n        struct nk_panel *root;\n        root = win->layout;\n        while (root) {\n            root->flags |= NK_WINDOW_REMOVE_ROM;\n            root = root->parent;\n        }\n        win->popup.buf.active = 0;\n        win->popup.active = 0;\n        ctx->memory.allocated = allocated;\n        ctx->current = win;\n        nk_free_panel(ctx, popup->layout);\n        popup->layout = 0;\n        return 0;\n    }\n}\nNK_LIB nk_bool\nnk_nonblock_begin(struct nk_context *ctx,\n    nk_flags flags, struct nk_rect body, struct nk_rect header,\n    enum nk_panel_type panel_type)\n{\n    struct nk_window *popup;\n    struct nk_window *win;\n    struct nk_panel *panel;\n    int is_active = nk_true;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    /* popups cannot have popups */\n    win = ctx->current;\n    panel = win->layout;\n    NK_ASSERT(!((int)panel->type & (int)NK_PANEL_SET_POPUP));\n    (void)panel;\n    popup = win->popup.win;\n    if (!popup) {\n        /* create window for nonblocking popup */\n        popup = (struct nk_window*)nk_create_window(ctx);\n        popup->parent = win;\n        win->popup.win = popup;\n        win->popup.type = panel_type;\n        nk_command_buffer_init(&popup->buffer, &ctx->memory, NK_CLIPPING_ON);\n    } else {\n        /* close the popup if user pressed outside or in the header */\n        int pressed, in_body, in_header;\n#ifdef NK_BUTTON_TRIGGER_ON_RELEASE\n        pressed = nk_input_is_mouse_released(&ctx->input, NK_BUTTON_LEFT);\n#else\n        pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);\n#endif\n        in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);\n        in_header = nk_input_is_mouse_hovering_rect(&ctx->input, header);\n        if (pressed && (!in_body || in_header))\n            is_active = nk_false;\n    }\n    win->popup.header = header;\n\n    if (!is_active) {\n        /* remove read only mode from all parent panels */\n        struct nk_panel *root = win->layout;\n        while (root) {\n            root->flags |= NK_WINDOW_REMOVE_ROM;\n            root = root->parent;\n        }\n        return is_active;\n    }\n    popup->bounds = body;\n    popup->parent = win;\n    popup->layout = (struct nk_panel*)nk_create_panel(ctx);\n    popup->flags = flags;\n    popup->flags |= NK_WINDOW_BORDER;\n    popup->flags |= NK_WINDOW_DYNAMIC;\n    popup->seq = ctx->seq;\n    win->popup.active = 1;\n    NK_ASSERT(popup->layout);\n\n    nk_start_popup(ctx, win);\n    popup->buffer = win->buffer;\n    nk_push_scissor(&popup->buffer, nk_null_rect);\n    ctx->current = popup;\n\n    nk_panel_begin(ctx, 0, panel_type);\n    win->buffer = popup->buffer;\n    popup->layout->parent = win->layout;\n    popup->layout->offset_x = &popup->scrollbar.x;\n    popup->layout->offset_y = &popup->scrollbar.y;\n\n    /* set read only mode to all parent panels */\n    {struct nk_panel *root;\n    root = win->layout;\n    while (root) {\n        root->flags |= NK_WINDOW_ROM;\n        root = root->parent;\n    }}\n    return is_active;\n}\nNK_API void\nnk_popup_close(struct nk_context *ctx)\n{\n    struct nk_window *popup;\n    NK_ASSERT(ctx);\n    if (!ctx || !ctx->current) return;\n\n    popup = ctx->current;\n    NK_ASSERT(popup->parent);\n    NK_ASSERT((int)popup->layout->type & (int)NK_PANEL_SET_POPUP);\n    popup->flags |= NK_WINDOW_HIDDEN;\n}\nNK_API void\nnk_popup_end(struct nk_context *ctx)\n{\n    struct nk_window *win;\n    struct nk_window *popup;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    popup = ctx->current;\n    if (!popup->parent) return;\n    win = popup->parent;\n    if (popup->flags & NK_WINDOW_HIDDEN) {\n        struct nk_panel *root;\n        root = win->layout;\n        while (root) {\n            root->flags |= NK_WINDOW_REMOVE_ROM;\n            root = root->parent;\n        }\n        win->popup.active = 0;\n    }\n    nk_push_scissor(&popup->buffer, nk_null_rect);\n    nk_end(ctx);\n\n    win->buffer = popup->buffer;\n    nk_finish_popup(ctx, win);\n    ctx->current = win;\n    nk_push_scissor(&win->buffer, win->layout->clip);\n}\nNK_API void\nnk_popup_get_scroll(const struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)\n{\n    struct nk_window *popup;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    popup = ctx->current;\n    if (offset_x)\n      *offset_x = popup->scrollbar.x;\n    if (offset_y)\n      *offset_y = popup->scrollbar.y;\n}\nNK_API void\nnk_popup_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y)\n{\n    struct nk_window *popup;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    popup = ctx->current;\n    popup->scrollbar.x = offset_x;\n    popup->scrollbar.y = offset_y;\n}\n"
  },
  {
    "path": "src/nuklear_progress.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                          PROGRESS\n *\n * ===============================================================*/\nNK_LIB nk_size\nnk_progress_behavior(nk_flags *state, struct nk_input *in,\n    struct nk_rect r, struct nk_rect cursor, nk_size max, nk_size value, nk_bool modifiable)\n{\n    int left_mouse_down = 0;\n    int left_mouse_click_in_cursor = 0;\n\n    nk_widget_state_reset(state);\n    if (!in || !modifiable) return value;\n    left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;\n    left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in,\n            NK_BUTTON_LEFT, cursor, nk_true);\n    if (nk_input_is_mouse_hovering_rect(in, r))\n        *state = NK_WIDGET_STATE_HOVERED;\n\n    if (in && left_mouse_down && left_mouse_click_in_cursor) {\n        if (left_mouse_down && left_mouse_click_in_cursor) {\n            float ratio = NK_MAX(0, (float)(in->mouse.pos.x - cursor.x)) / (float)cursor.w;\n            value = (nk_size)NK_CLAMP(0, (float)max * ratio, (float)max);\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor.x + cursor.w/2.0f;\n            *state |= NK_WIDGET_STATE_ACTIVE;\n        }\n    }\n    /* set progressbar widget state */\n    if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, r))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, r))\n        *state |= NK_WIDGET_STATE_LEFT;\n    return value;\n}\nNK_LIB void\nnk_draw_progress(struct nk_command_buffer *out, nk_flags state,\n    const struct nk_style_progress *style, const struct nk_rect *bounds,\n    const struct nk_rect *scursor, nk_size value, nk_size max)\n{\n    const struct nk_style_item *background;\n    const struct nk_style_item *cursor;\n\n    NK_UNUSED(max);\n    NK_UNUSED(value);\n\n    /* select correct colors/images to draw */\n    if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->active;\n        cursor = &style->cursor_active;\n    } else if (state & NK_WIDGET_STATE_HOVER){\n        background = &style->hover;\n        cursor = &style->cursor_hover;\n    } else {\n        background = &style->normal;\n        cursor = &style->cursor_normal;\n    }\n\n    /* draw background */\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));\n            nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));\n            break;\n    }\n\n    /* draw cursor */\n    switch(cursor->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *scursor, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *scursor, &cursor->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *scursor, style->rounding, nk_rgb_factor(cursor->data.color, style->color_factor));\n            nk_stroke_rect(out, *scursor, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));\n            break;\n    }\n}\nNK_LIB nk_size\nnk_do_progress(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    nk_size value, nk_size max, nk_bool modifiable,\n    const struct nk_style_progress *style, struct nk_input *in)\n{\n    float prog_scale;\n    nk_size prog_value;\n    struct nk_rect cursor;\n\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    if (!out || !style) return 0;\n\n    /* calculate progressbar cursor */\n    cursor.w = NK_MAX(bounds.w, 2 * style->padding.x + 2 * style->border);\n    cursor.h = NK_MAX(bounds.h, 2 * style->padding.y + 2 * style->border);\n    cursor = nk_pad_rect(bounds, nk_vec2(style->padding.x + style->border, style->padding.y + style->border));\n    prog_scale = (float)value / (float)max;\n\n    /* update progressbar */\n    prog_value = NK_MIN(value, max);\n    prog_value = nk_progress_behavior(state, in, bounds, cursor,max, prog_value, modifiable);\n    cursor.w = cursor.w * prog_scale;\n\n    /* draw progressbar */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_progress(out, *state, style, &bounds, &cursor, value, max);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return prog_value;\n}\nNK_API nk_bool\nnk_progress(struct nk_context *ctx, nk_size *cur, nk_size max, nk_bool is_modifyable)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_style *style;\n    struct nk_input *in;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n    nk_size old_value;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(cur);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !cur)\n        return 0;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    old_value = *cur;\n    *cur = nk_do_progress(&ctx->last_widget_state, &win->buffer, bounds,\n            *cur, max, is_modifyable, &style->progress, in);\n    return (*cur != old_value);\n}\nNK_API nk_size\nnk_prog(struct nk_context *ctx, nk_size cur, nk_size max, nk_bool modifyable)\n{\n    nk_progress(ctx, &cur, max, modifyable);\n    return cur;\n}\n\n"
  },
  {
    "path": "src/nuklear_property.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              PROPERTY\n *\n * ===============================================================*/\nNK_LIB void\nnk_drag_behavior(nk_flags *state, const struct nk_input *in,\n    struct nk_rect drag, struct nk_property_variant *variant,\n    float inc_per_pixel)\n{\n    int left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;\n    int left_mouse_click_in_cursor = in &&\n        nk_input_has_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, drag, nk_true);\n\n    nk_widget_state_reset(state);\n    if (nk_input_is_mouse_hovering_rect(in, drag))\n        *state = NK_WIDGET_STATE_HOVERED;\n\n    if (left_mouse_down && left_mouse_click_in_cursor) {\n        float delta, pixels;\n        pixels = in->mouse.delta.x;\n        delta = pixels * inc_per_pixel;\n        switch (variant->kind) {\n        default: break;\n        case NK_PROPERTY_INT:\n            variant->value.i = variant->value.i + (int)delta;\n            variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);\n            break;\n        case NK_PROPERTY_FLOAT:\n            variant->value.f = variant->value.f + (float)delta;\n            variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);\n            break;\n        case NK_PROPERTY_DOUBLE:\n            variant->value.d = variant->value.d + (double)delta;\n            variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);\n            break;\n        }\n        *state = NK_WIDGET_STATE_ACTIVE;\n    }\n    if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, drag))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, drag))\n        *state |= NK_WIDGET_STATE_LEFT;\n}\nNK_LIB void\nnk_property_behavior(nk_flags *ws, const struct nk_input *in,\n    struct nk_rect property,  struct nk_rect label, struct nk_rect edit,\n    struct nk_rect empty, int *state, struct nk_property_variant *variant,\n    float inc_per_pixel)\n{\n    nk_widget_state_reset(ws);\n    if (in && *state == NK_PROPERTY_DEFAULT) {\n        if (nk_button_behavior(ws, edit, in, NK_BUTTON_DEFAULT))\n            *state = NK_PROPERTY_EDIT;\n        else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, label, nk_true))\n            *state = NK_PROPERTY_DRAG;\n        else if (nk_input_is_mouse_click_down_in_rect(in, NK_BUTTON_LEFT, empty, nk_true))\n            *state = NK_PROPERTY_DRAG;\n    }\n    if (*state == NK_PROPERTY_DRAG) {\n        nk_drag_behavior(ws, in, property, variant, inc_per_pixel);\n        if (!(*ws & NK_WIDGET_STATE_ACTIVED)) *state = NK_PROPERTY_DEFAULT;\n    }\n}\nNK_LIB void\nnk_draw_property(struct nk_command_buffer *out, const struct nk_style_property *style,\n    const struct nk_rect *bounds, const struct nk_rect *label, nk_flags state,\n    const char *name, int len, const struct nk_user_font *font)\n{\n    struct nk_text text;\n    const struct nk_style_item *background;\n\n    /* select correct background and text color */\n    if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->active;\n        text.text = style->label_active;\n    } else if (state & NK_WIDGET_STATE_HOVER) {\n        background = &style->hover;\n        text.text = style->label_hover;\n    } else {\n        background = &style->normal;\n        text.text = style->label_normal;\n    }\n\n    text.text = nk_rgb_factor(text.text, style->color_factor);\n\n    /* draw background */\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            text.background = background->data.color;\n            nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));\n            nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));\n            break;\n    }\n\n    /* draw label */\n    text.padding = nk_vec2(0,0);\n    if (name && name[0] != '#') {\n        nk_widget_text(out, *label, name, len, &text, NK_TEXT_CENTERED, font);\n    }\n}\nNK_INTERN void\nnk_property_save(struct nk_property_variant *variant, char *buffer, int len)\n{\n    buffer[len] = '\\0';\n    switch (variant->kind) {\n    default: break;\n    case NK_PROPERTY_INT:\n        variant->value.i = nk_strtoi(buffer, 0);\n        variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i, variant->max_value.i);\n        break;\n    case NK_PROPERTY_FLOAT:\n        nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);\n        variant->value.f = nk_strtof(buffer, 0);\n        variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f, variant->max_value.f);\n        break;\n    case NK_PROPERTY_DOUBLE:\n        nk_string_float_limit(buffer, NK_MAX_FLOAT_PRECISION);\n        variant->value.d = NK_STRTOD(buffer, 0);\n        variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d, variant->max_value.d);\n        break;\n    }\n}\nNK_LIB void\nnk_do_property(nk_flags *ws,\n    struct nk_command_buffer *out, struct nk_rect property,\n    const char *name, struct nk_property_variant *variant,\n    float inc_per_pixel, char *buffer, int *len,\n    int *state, int *cursor, int *select_begin, int *select_end,\n    const struct nk_style_property *style,\n    enum nk_property_filter filter, struct nk_input *in,\n    const struct nk_user_font *font, struct nk_text_edit *text_edit,\n    enum nk_button_behavior behavior)\n{\n    const nk_plugin_filter filters[] = {\n        nk_filter_decimal,\n        nk_filter_float\n    };\n    nk_bool active, old;\n    int num_len = 0, name_len = 0;\n    char string[NK_MAX_NUMBER_BUFFER];\n    float size;\n\n    char *dst = 0;\n    int *length;\n\n    struct nk_rect left;\n    struct nk_rect right;\n    struct nk_rect label;\n    struct nk_rect edit;\n    struct nk_rect empty;\n\n    /* left decrement button */\n    left.h = font->height/2;\n    left.w = left.h;\n    left.x = property.x + style->border + style->padding.x;\n    left.y = property.y + style->border + property.h/2.0f - left.h/2;\n\n    /* text label */\n    if (name && name[0] != '#') {\n        name_len = nk_strlen(name);\n    }\n    size = font->width(font->userdata, font->height, name, name_len);\n    label.x = left.x + left.w + style->padding.x;\n    label.w = (float)size + 2 * style->padding.x;\n    label.y = property.y + style->border + style->padding.y;\n    label.h = property.h - (2 * style->border + 2 * style->padding.y);\n\n    /* right increment button */\n    right.y = left.y;\n    right.w = left.w;\n    right.h = left.h;\n    right.x = property.x + property.w - (right.w + style->padding.x);\n\n    /* edit */\n    if (*state == NK_PROPERTY_EDIT) {\n        size = font->width(font->userdata, font->height, buffer, *len);\n        size += style->edit.cursor_size;\n        length = len;\n        dst = buffer;\n    } else {\n        switch (variant->kind) {\n        default: break;\n        case NK_PROPERTY_INT:\n            nk_itoa(string, variant->value.i);\n            num_len = nk_strlen(string);\n            break;\n        case NK_PROPERTY_FLOAT:\n            NK_DTOA(string, (double)variant->value.f);\n            num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);\n            break;\n        case NK_PROPERTY_DOUBLE:\n            NK_DTOA(string, variant->value.d);\n            num_len = nk_string_float_limit(string, NK_MAX_FLOAT_PRECISION);\n            break;\n        }\n        size = font->width(font->userdata, font->height, string, num_len);\n        dst = string;\n        length = &num_len;\n    }\n\n    edit.w =  (float)size + 2 * style->padding.x;\n    edit.w = NK_MIN(edit.w, right.x - (label.x + label.w));\n    edit.x = right.x - (edit.w + style->padding.x);\n    edit.y = property.y + style->border;\n    edit.h = property.h - (2 * style->border);\n\n    /* empty left space activator */\n    empty.w = edit.x - (label.x + label.w);\n    empty.x = label.x + label.w;\n    empty.y = property.y;\n    empty.h = property.h;\n\n    /* update property */\n    old = (*state == NK_PROPERTY_EDIT);\n    nk_property_behavior(ws, in, property, label, edit, empty, state, variant, inc_per_pixel);\n\n    /* draw property */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_property(out, style, &property, &label, *ws, name, name_len, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n\n    /* execute right button  */\n    if (nk_do_button_symbol(ws, out, left, style->sym_left, behavior, &style->dec_button, in, font)) {\n        switch (variant->kind) {\n        default: break;\n        case NK_PROPERTY_INT:\n            variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i - variant->step.i, variant->max_value.i); break;\n        case NK_PROPERTY_FLOAT:\n            variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f - variant->step.f, variant->max_value.f); break;\n        case NK_PROPERTY_DOUBLE:\n            variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d - variant->step.d, variant->max_value.d); break;\n        }\n    }\n    /* execute left button  */\n    if (nk_do_button_symbol(ws, out, right, style->sym_right, behavior, &style->inc_button, in, font)) {\n        switch (variant->kind) {\n        default: break;\n        case NK_PROPERTY_INT:\n            variant->value.i = NK_CLAMP(variant->min_value.i, variant->value.i + variant->step.i, variant->max_value.i); break;\n        case NK_PROPERTY_FLOAT:\n            variant->value.f = NK_CLAMP(variant->min_value.f, variant->value.f + variant->step.f, variant->max_value.f); break;\n        case NK_PROPERTY_DOUBLE:\n            variant->value.d = NK_CLAMP(variant->min_value.d, variant->value.d + variant->step.d, variant->max_value.d); break;\n        }\n    }\n    if (!old && (*state == NK_PROPERTY_EDIT)) {\n        /* property has been activated so setup buffer */\n        NK_MEMCPY(buffer, dst, (nk_size)*length);\n        *cursor = nk_utf_len(buffer, *length);\n        *len = *length;\n        length = len;\n        dst = buffer;\n        active = 0;\n    } else active = (*state == NK_PROPERTY_EDIT);\n\n    /* execute and run text edit field */\n    nk_textedit_clear_state(text_edit, NK_TEXT_EDIT_SINGLE_LINE, filters[filter]);\n    text_edit->active = (unsigned char)active;\n    text_edit->string.len = *length;\n    text_edit->cursor = NK_CLAMP(0, *cursor, *length);\n    text_edit->select_start = NK_CLAMP(0,*select_begin, *length);\n    text_edit->select_end = NK_CLAMP(0,*select_end, *length);\n    text_edit->string.buffer.allocated = (nk_size)*length;\n    text_edit->string.buffer.memory.size = NK_MAX_NUMBER_BUFFER;\n    text_edit->string.buffer.memory.ptr = dst;\n    text_edit->string.buffer.size = NK_MAX_NUMBER_BUFFER;\n    text_edit->mode = NK_TEXT_EDIT_MODE_INSERT;\n    nk_do_edit(ws, out, edit, (int)NK_EDIT_FIELD|(int)NK_EDIT_AUTO_SELECT,\n        filters[filter], text_edit, &style->edit, (*state == NK_PROPERTY_EDIT) ? in: 0, font);\n\n    *length = text_edit->string.len;\n    *cursor = text_edit->cursor;\n    *select_begin = text_edit->select_start;\n    *select_end = text_edit->select_end;\n    if (text_edit->active && nk_input_is_key_pressed(in, NK_KEY_ENTER))\n        text_edit->active = nk_false;\n\n    if (active && !text_edit->active) {\n        /* property is now not active so convert edit text to value*/\n        *state = NK_PROPERTY_DEFAULT;\n        nk_property_save(variant, buffer, *len);\n    }\n}\nNK_LIB struct nk_property_variant\nnk_property_variant_int(int value, int min_value, int max_value, int step)\n{\n    struct nk_property_variant result;\n    result.kind = NK_PROPERTY_INT;\n    result.value.i = value;\n    result.min_value.i = min_value;\n    result.max_value.i = max_value;\n    result.step.i = step;\n    return result;\n}\nNK_LIB struct nk_property_variant\nnk_property_variant_float(float value, float min_value, float max_value, float step)\n{\n    struct nk_property_variant result;\n    result.kind = NK_PROPERTY_FLOAT;\n    result.value.f = value;\n    result.min_value.f = min_value;\n    result.max_value.f = max_value;\n    result.step.f = step;\n    return result;\n}\nNK_LIB struct nk_property_variant\nnk_property_variant_double(double value, double min_value, double max_value,\n    double step)\n{\n    struct nk_property_variant result;\n    result.kind = NK_PROPERTY_DOUBLE;\n    result.value.d = value;\n    result.min_value.d = min_value;\n    result.max_value.d = max_value;\n    result.step.d = step;\n    return result;\n}\nNK_LIB void\nnk_property(struct nk_context *ctx, const char *name, struct nk_property_variant *variant,\n    float inc_per_pixel, const enum nk_property_filter filter)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states s;\n    nk_bool hot;\n\n    int *state = 0;\n    nk_hash hash = 0;\n    char *buffer = 0;\n    int *len = 0;\n    int *cursor = 0;\n    int *select_begin = 0;\n    int *select_end = 0;\n    int old_state;\n    int prev_state;\n\n    char dummy_buffer[NK_MAX_NUMBER_BUFFER];\n    int dummy_state = NK_PROPERTY_DEFAULT;\n    int dummy_length = 0;\n    int dummy_cursor = 0;\n    int dummy_select_begin = 0;\n    int dummy_select_end = 0;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    style = &ctx->style;\n    s = nk_widget(&bounds, ctx);\n    if (!s) return;\n\n    /* calculate hash from name */\n    if (name[0] == '#') {\n        hash = nk_murmur_hash(name, (int)nk_strlen(name), win->property.seq++);\n        name++; /* special number hash */\n    } else hash = nk_murmur_hash(name, (int)nk_strlen(name), 42);\n\n    /* check if property is previously hot */\n    if (win->property.prev_state == NK_PROPERTY_EDIT && hash == win->property.prev_name) {\n        nk_property_save(variant, win->property.prev_buffer, win->property.prev_length);\n        win->property.prev_state = NK_PROPERTY_DEFAULT;\n    }\n\n    /* check if property is currently hot item */\n    hot = win->property.active && hash == win->property.name;\n    if (hot) {\n        buffer = win->property.buffer;\n        len = &win->property.length;\n        cursor = &win->property.cursor;\n        state = &win->property.state;\n        select_begin = &win->property.select_start;\n        select_end = &win->property.select_end;\n    } else {\n        buffer = dummy_buffer;\n        len = &dummy_length;\n        cursor = &dummy_cursor;\n        state = &dummy_state;\n        select_begin =  &dummy_select_begin;\n        select_end = &dummy_select_end;\n    }\n\n    /* execute property widget */\n    old_state = *state;\n    prev_state = win->property.state;\n    ctx->text_edit.clip = ctx->clip;\n    in = ((s == NK_WIDGET_ROM && !win->property.active) ||\n        layout->flags & NK_WINDOW_ROM || s == NK_WIDGET_DISABLED) ? 0 : &ctx->input;\n    nk_do_property(&ctx->last_widget_state, &win->buffer, bounds, name,\n        variant, inc_per_pixel, buffer, len, state, cursor, select_begin,\n        select_end, &style->property, filter, in, style->font, &ctx->text_edit,\n        ctx->button_behavior);\n\n    if (in && *state != NK_PROPERTY_DEFAULT && !hot) {\n        /* another property was active */\n        if (win->property.active /* && hash != win->property.name */) {\n            win->property.prev_state = prev_state;\n            win->property.prev_name = win->property.name;\n            win->property.prev_length = win->property.length;\n            NK_MEMCPY(win->property.prev_buffer, win->property.buffer, win->property.length);\n        }\n        /* current property is now hot */\n        win->property.active = 1;\n        NK_MEMCPY(win->property.buffer, buffer, (nk_size)*len);\n        win->property.length = *len;\n        win->property.cursor = *cursor;\n        win->property.state = *state;\n        win->property.name = hash;\n        win->property.select_start = *select_begin;\n        win->property.select_end = *select_end;\n        win->edit.active = nk_true;\n        if (*state == NK_PROPERTY_DRAG) {\n            ctx->input.mouse.grab = nk_true;\n            ctx->input.mouse.grabbed = nk_true;\n        }\n    }\n    /* check if previously active property is now inactive */\n    if (*state == NK_PROPERTY_DEFAULT && old_state != NK_PROPERTY_DEFAULT) {\n        if (old_state == NK_PROPERTY_DRAG) {\n            ctx->input.mouse.grab = nk_false;\n            ctx->input.mouse.grabbed = nk_false;\n            ctx->input.mouse.ungrab = nk_true;\n        }\n        win->property.select_start = 0;\n        win->property.select_end = 0;\n        win->property.active = 0;\n        win->edit.active = nk_false;\n    }\n}\nNK_API nk_bool\nnk_property_int(struct nk_context *ctx, const char *name,\n    int min, int *val, int max, int step, float inc_per_pixel)\n{\n    struct nk_property_variant variant;\n    nk_bool changed;\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n    NK_ASSERT(val);\n\n    if (!ctx || !ctx->current || !name || !val) return nk_false;\n    variant = nk_property_variant_int(*val, min, max, step);\n    nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);\n    changed = variant.value.i != *val;\n    *val = variant.value.i;\n    return changed;\n}\nNK_API nk_bool\nnk_property_float(struct nk_context *ctx, const char *name,\n    float min, float *val, float max, float step, float inc_per_pixel)\n{\n    struct nk_property_variant variant;\n    nk_bool changed;\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n    NK_ASSERT(val);\n\n    if (!ctx || !ctx->current || !name || !val) return nk_false;\n    variant = nk_property_variant_float(*val, min, max, step);\n    nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);\n    changed = variant.value.f != *val;\n    *val = variant.value.f;\n    return changed;\n}\nNK_API nk_bool\nnk_property_double(struct nk_context *ctx, const char *name,\n    double min, double *val, double max, double step, float inc_per_pixel)\n{\n    struct nk_property_variant variant;\n    nk_bool changed;\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n    NK_ASSERT(val);\n\n    if (!ctx || !ctx->current || !name || !val) return nk_false;\n    variant = nk_property_variant_double(*val, min, max, step);\n    nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);\n    changed = variant.value.d != *val;\n    *val = variant.value.d;\n    return changed;\n}\nNK_API int\nnk_propertyi(struct nk_context *ctx, const char *name, int min, int val,\n    int max, int step, float inc_per_pixel)\n{\n    struct nk_property_variant variant;\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n\n    if (!ctx || !ctx->current || !name) return val;\n    variant = nk_property_variant_int(val, min, max, step);\n    nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_INT);\n    val = variant.value.i;\n    return val;\n}\nNK_API float\nnk_propertyf(struct nk_context *ctx, const char *name, float min,\n    float val, float max, float step, float inc_per_pixel)\n{\n    struct nk_property_variant variant;\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n\n    if (!ctx || !ctx->current || !name) return val;\n    variant = nk_property_variant_float(val, min, max, step);\n    nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);\n    val = variant.value.f;\n    return val;\n}\nNK_API double\nnk_propertyd(struct nk_context *ctx, const char *name, double min,\n    double val, double max, double step, float inc_per_pixel)\n{\n    struct nk_property_variant variant;\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n\n    if (!ctx || !ctx->current || !name) return val;\n    variant = nk_property_variant_double(val, min, max, step);\n    nk_property(ctx, name, &variant, inc_per_pixel, NK_FILTER_FLOAT);\n    val = variant.value.d;\n    return val;\n}\n\n"
  },
  {
    "path": "src/nuklear_scrollbar.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              SCROLLBAR\n *\n * ===============================================================*/\nNK_LIB float\nnk_scrollbar_behavior(nk_flags *state, struct nk_input *in,\n    int has_scrolling, const struct nk_rect *scroll,\n    const struct nk_rect *cursor, const struct nk_rect *empty0,\n    const struct nk_rect *empty1, float scroll_offset,\n    float target, float scroll_step, enum nk_orientation o)\n{\n    nk_flags ws = 0;\n    int left_mouse_down;\n    unsigned int left_mouse_clicked;\n    int left_mouse_click_in_cursor;\n    float scroll_delta;\n\n    nk_widget_state_reset(state);\n    if (!in) return scroll_offset;\n\n    left_mouse_down = in->mouse.buttons[NK_BUTTON_LEFT].down;\n    left_mouse_clicked = in->mouse.buttons[NK_BUTTON_LEFT].clicked;\n    left_mouse_click_in_cursor = nk_input_has_mouse_click_down_in_rect(in,\n        NK_BUTTON_LEFT, *cursor, nk_true);\n    if (nk_input_is_mouse_hovering_rect(in, *scroll))\n        *state = NK_WIDGET_STATE_HOVERED;\n\n    scroll_delta = (o == NK_VERTICAL) ? in->mouse.scroll_delta.y: in->mouse.scroll_delta.x;\n    if (left_mouse_down && left_mouse_click_in_cursor && !left_mouse_clicked) {\n        /* update cursor by mouse dragging */\n        float pixel, delta;\n        *state = NK_WIDGET_STATE_ACTIVE;\n        if (o == NK_VERTICAL) {\n            float cursor_y;\n            pixel = in->mouse.delta.y;\n            delta = (pixel / scroll->h) * target;\n            scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->h);\n            cursor_y = scroll->y + ((scroll_offset/target) * scroll->h);\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.y = cursor_y + cursor->h/2.0f;\n        } else {\n            float cursor_x;\n            pixel = in->mouse.delta.x;\n            delta = (pixel / scroll->w) * target;\n            scroll_offset = NK_CLAMP(0, scroll_offset + delta, target - scroll->w);\n            cursor_x = scroll->x + ((scroll_offset/target) * scroll->w);\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = cursor_x + cursor->w/2.0f;\n        }\n    } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_UP) && o == NK_VERTICAL && has_scrolling)||\n            nk_button_behavior(&ws, *empty0, in, NK_BUTTON_DEFAULT)) {\n        /* scroll page up by click on empty space or shortcut */\n        if (o == NK_VERTICAL)\n            scroll_offset = NK_MAX(0, scroll_offset - scroll->h);\n        else scroll_offset = NK_MAX(0, scroll_offset - scroll->w);\n    } else if ((nk_input_is_key_pressed(in, NK_KEY_SCROLL_DOWN) && o == NK_VERTICAL && has_scrolling) ||\n        nk_button_behavior(&ws, *empty1, in, NK_BUTTON_DEFAULT)) {\n        /* scroll page down by click on empty space or shortcut */\n        if (o == NK_VERTICAL)\n            scroll_offset = NK_MIN(scroll_offset + scroll->h, target - scroll->h);\n        else scroll_offset = NK_MIN(scroll_offset + scroll->w, target - scroll->w);\n    } else if (has_scrolling) {\n        if ((scroll_delta < 0 || (scroll_delta > 0))) {\n            /* update cursor by mouse scrolling */\n            scroll_offset = scroll_offset + scroll_step * (-scroll_delta);\n            if (o == NK_VERTICAL)\n                scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->h);\n            else scroll_offset = NK_CLAMP(0, scroll_offset, target - scroll->w);\n        } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_START)) {\n            /* update cursor to the beginning  */\n            if (o == NK_VERTICAL) scroll_offset = 0;\n        } else if (nk_input_is_key_pressed(in, NK_KEY_SCROLL_END)) {\n            /* update cursor to the end */\n            if (o == NK_VERTICAL) scroll_offset = target - scroll->h;\n        }\n    }\n    if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, *scroll))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, *scroll))\n        *state |= NK_WIDGET_STATE_LEFT;\n    return scroll_offset;\n}\nNK_LIB void\nnk_draw_scrollbar(struct nk_command_buffer *out, nk_flags state,\n    const struct nk_style_scrollbar *style, const struct nk_rect *bounds,\n    const struct nk_rect *scroll)\n{\n    const struct nk_style_item *background;\n    const struct nk_style_item *cursor;\n\n    /* select correct colors/images to draw */\n    if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->active;\n        cursor = &style->cursor_active;\n    } else if (state & NK_WIDGET_STATE_HOVER) {\n        background = &style->hover;\n        cursor = &style->cursor_hover;\n    } else {\n        background = &style->normal;\n        cursor = &style->cursor_normal;\n    }\n\n    /* draw background */\n    switch (background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *bounds, &background->data.image, nk_white);\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_white);\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *bounds, style->rounding, background->data.color);\n            nk_stroke_rect(out, *bounds, style->rounding, style->border, style->border_color);\n            break;\n    }\n\n    /* draw cursor */\n    switch (cursor->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *scroll, &cursor->data.image, nk_white);\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *scroll, &cursor->data.slice, nk_white);\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *scroll, style->rounding_cursor, cursor->data.color);\n            nk_stroke_rect(out, *scroll, style->rounding_cursor, style->border_cursor, style->cursor_border_color);\n            break;\n    }\n}\nNK_LIB float\nnk_do_scrollbarv(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling,\n    float offset, float target, float step, float button_pixel_inc,\n    const struct nk_style_scrollbar *style, struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    struct nk_rect empty_north;\n    struct nk_rect empty_south;\n    struct nk_rect cursor;\n\n    float scroll_step;\n    float scroll_offset;\n    float scroll_off;\n    float scroll_ratio;\n\n    NK_ASSERT(out);\n    NK_ASSERT(style);\n    NK_ASSERT(state);\n    if (!out || !style) return 0;\n\n    scroll.w = NK_MAX(scroll.w, 1);\n    scroll.h = NK_MAX(scroll.h, 0);\n    if (target <= scroll.h) return 0;\n\n    /* optional scrollbar buttons */\n    if (style->show_buttons) {\n        nk_flags ws;\n        float scroll_h;\n        struct nk_rect button;\n\n        button.x = scroll.x;\n        button.w = scroll.w;\n        button.h = scroll.w;\n\n        scroll_h = NK_MAX(scroll.h - 2 * button.h,0);\n        scroll_step = NK_MIN(step, button_pixel_inc);\n\n        /* decrement button */\n        button.y = scroll.y;\n        if (nk_do_button_symbol(&ws, out, button, style->dec_symbol,\n            NK_BUTTON_REPEATER, &style->dec_button, in, font))\n            offset = offset - scroll_step;\n\n        /* increment button */\n        button.y = scroll.y + scroll.h - button.h;\n        if (nk_do_button_symbol(&ws, out, button, style->inc_symbol,\n            NK_BUTTON_REPEATER, &style->inc_button, in, font))\n            offset = offset + scroll_step;\n\n        scroll.y = scroll.y + button.h;\n        scroll.h = scroll_h;\n    }\n\n    /* calculate scrollbar constants */\n    scroll_step = NK_MIN(step, scroll.h);\n    scroll_offset = NK_CLAMP(0, offset, target - scroll.h);\n    scroll_ratio = scroll.h / target;\n    scroll_off = scroll_offset / target;\n\n    /* calculate scrollbar cursor bounds */\n    cursor.h = NK_MAX((scroll_ratio * scroll.h) - (2*style->border + 2*style->padding.y), 0);\n    cursor.y = scroll.y + (scroll_off * scroll.h) + style->border + style->padding.y;\n    cursor.w = scroll.w - (2 * style->border + 2 * style->padding.x);\n    cursor.x = scroll.x + style->border + style->padding.x;\n\n    /* calculate empty space around cursor */\n    empty_north.x = scroll.x;\n    empty_north.y = scroll.y;\n    empty_north.w = scroll.w;\n    empty_north.h = NK_MAX(cursor.y - scroll.y, 0);\n\n    empty_south.x = scroll.x;\n    empty_south.y = cursor.y + cursor.h;\n    empty_south.w = scroll.w;\n    empty_south.h = NK_MAX((scroll.y + scroll.h) - (cursor.y + cursor.h), 0);\n\n    /* update scrollbar */\n    scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor,\n        &empty_north, &empty_south, scroll_offset, target, scroll_step, NK_VERTICAL);\n    scroll_off = scroll_offset / target;\n    cursor.y = scroll.y + (scroll_off * scroll.h) + style->border_cursor + style->padding.y;\n\n    /* draw scrollbar */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_scrollbar(out, *state, style, &scroll, &cursor);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return scroll_offset;\n}\nNK_LIB float\nnk_do_scrollbarh(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect scroll, int has_scrolling,\n    float offset, float target, float step, float button_pixel_inc,\n    const struct nk_style_scrollbar *style, struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    struct nk_rect cursor;\n    struct nk_rect empty_west;\n    struct nk_rect empty_east;\n\n    float scroll_step;\n    float scroll_offset;\n    float scroll_off;\n    float scroll_ratio;\n\n    NK_ASSERT(out);\n    NK_ASSERT(style);\n    if (!out || !style) return 0;\n\n    /* scrollbar background */\n    scroll.h = NK_MAX(scroll.h, 1);\n    scroll.w = NK_MAX(scroll.w, 2 * scroll.h);\n    if (target <= scroll.w) return 0;\n\n    /* optional scrollbar buttons */\n    if (style->show_buttons) {\n        nk_flags ws;\n        float scroll_w;\n        struct nk_rect button;\n        button.y = scroll.y;\n        button.w = scroll.h;\n        button.h = scroll.h;\n\n        scroll_w = scroll.w - 2 * button.w;\n        scroll_step = NK_MIN(step, button_pixel_inc);\n\n        /* decrement button */\n        button.x = scroll.x;\n        if (nk_do_button_symbol(&ws, out, button, style->dec_symbol,\n            NK_BUTTON_REPEATER, &style->dec_button, in, font))\n            offset = offset - scroll_step;\n\n        /* increment button */\n        button.x = scroll.x + scroll.w - button.w;\n        if (nk_do_button_symbol(&ws, out, button, style->inc_symbol,\n            NK_BUTTON_REPEATER, &style->inc_button, in, font))\n            offset = offset + scroll_step;\n\n        scroll.x = scroll.x + button.w;\n        scroll.w = scroll_w;\n    }\n\n    /* calculate scrollbar constants */\n    scroll_step = NK_MIN(step, scroll.w);\n    scroll_offset = NK_CLAMP(0, offset, target - scroll.w);\n    scroll_ratio = scroll.w / target;\n    scroll_off = scroll_offset / target;\n\n    /* calculate cursor bounds */\n    cursor.w = (scroll_ratio * scroll.w) - (2*style->border + 2*style->padding.x);\n    cursor.x = scroll.x + (scroll_off * scroll.w) + style->border + style->padding.x;\n    cursor.h = scroll.h - (2 * style->border + 2 * style->padding.y);\n    cursor.y = scroll.y + style->border + style->padding.y;\n\n    /* calculate empty space around cursor */\n    empty_west.x = scroll.x;\n    empty_west.y = scroll.y;\n    empty_west.w = cursor.x - scroll.x;\n    empty_west.h = scroll.h;\n\n    empty_east.x = cursor.x + cursor.w;\n    empty_east.y = scroll.y;\n    empty_east.w = (scroll.x + scroll.w) - (cursor.x + cursor.w);\n    empty_east.h = scroll.h;\n\n    /* update scrollbar */\n    scroll_offset = nk_scrollbar_behavior(state, in, has_scrolling, &scroll, &cursor,\n        &empty_west, &empty_east, scroll_offset, target, scroll_step, NK_HORIZONTAL);\n    scroll_off = scroll_offset / target;\n    cursor.x = scroll.x + (scroll_off * scroll.w);\n\n    /* draw scrollbar */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_scrollbar(out, *state, style, &scroll, &cursor);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return scroll_offset;\n}\n\n"
  },
  {
    "path": "src/nuklear_selectable.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              SELECTABLE\n *\n * ===============================================================*/\nNK_LIB void\nnk_draw_selectable(struct nk_command_buffer *out,\n    nk_flags state, const struct nk_style_selectable *style, nk_bool active,\n    const struct nk_rect *bounds,\n    const struct nk_rect *icon, const struct nk_image *img, enum nk_symbol_type sym,\n    const char *string, int len, nk_flags align, const struct nk_user_font *font)\n{\n    const struct nk_style_item *background;\n    struct nk_text text;\n    text.padding = style->padding;\n\n    /* select correct colors/images */\n    if (!active) {\n        if (state & NK_WIDGET_STATE_ACTIVED) {\n            background = &style->pressed;\n            text.text = style->text_pressed;\n        } else if (state & NK_WIDGET_STATE_HOVER) {\n            background = &style->hover;\n            text.text = style->text_hover;\n        } else {\n            background = &style->normal;\n            text.text = style->text_normal;\n        }\n    } else {\n        if (state & NK_WIDGET_STATE_ACTIVED) {\n            background = &style->pressed_active;\n            text.text = style->text_pressed_active;\n        } else if (state & NK_WIDGET_STATE_HOVER) {\n            background = &style->hover_active;\n            text.text = style->text_hover_active;\n        } else {\n            background = &style->normal_active;\n            text.text = style->text_normal_active;\n        }\n    }\n\n    text.text = nk_rgb_factor(text.text, style->color_factor);\n\n    /* draw selectable background and text */\n    switch (background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            text.background = nk_rgba(0, 0, 0, 0);\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            text.background = background->data.color;\n            nk_fill_rect(out, *bounds, style->rounding, background->data.color);\n            break;\n    }\n    if (icon) {\n        if (img) nk_draw_image(out, *icon, img, nk_rgb_factor(nk_white, style->color_factor));\n        else nk_draw_symbol(out, sym, *icon, text.background, text.text, 1, font);\n    }\n    nk_widget_text(out, *bounds, string, len, &text, align, font);\n}\nNK_LIB nk_bool\nnk_do_selectable(nk_flags *state, struct nk_command_buffer *out,\n    struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value,\n    const struct nk_style_selectable *style, const struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    int old_value;\n    struct nk_rect touch;\n\n    NK_ASSERT(state);\n    NK_ASSERT(out);\n    NK_ASSERT(str);\n    NK_ASSERT(len);\n    NK_ASSERT(value);\n    NK_ASSERT(style);\n    NK_ASSERT(font);\n\n    if (!state || !out || !str || !len || !value || !style || !font) return 0;\n    old_value = *value;\n\n    /* remove padding */\n    touch.x = bounds.x - style->touch_padding.x;\n    touch.y = bounds.y - style->touch_padding.y;\n    touch.w = bounds.w + style->touch_padding.x * 2;\n    touch.h = bounds.h + style->touch_padding.y * 2;\n\n    /* update button */\n    if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))\n        *value = !(*value);\n\n    /* draw selectable */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_selectable(out, *state, style, *value, &bounds, 0,0,NK_SYMBOL_NONE, str, len, align, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return old_value != *value;\n}\nNK_LIB nk_bool\nnk_do_selectable_image(nk_flags *state, struct nk_command_buffer *out,\n    struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value,\n    const struct nk_image *img, const struct nk_style_selectable *style,\n    const struct nk_input *in, const struct nk_user_font *font)\n{\n    nk_bool old_value;\n    struct nk_rect touch;\n    struct nk_rect icon;\n\n    NK_ASSERT(state);\n    NK_ASSERT(out);\n    NK_ASSERT(str);\n    NK_ASSERT(len);\n    NK_ASSERT(value);\n    NK_ASSERT(style);\n    NK_ASSERT(font);\n\n    if (!state || !out || !str || !len || !value || !style || !font) return 0;\n    old_value = *value;\n\n    /* toggle behavior */\n    touch.x = bounds.x - style->touch_padding.x;\n    touch.y = bounds.y - style->touch_padding.y;\n    touch.w = bounds.w + style->touch_padding.x * 2;\n    touch.h = bounds.h + style->touch_padding.y * 2;\n    if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))\n        *value = !(*value);\n\n    icon.y = bounds.y + style->padding.y;\n    icon.w = icon.h = bounds.h - 2 * style->padding.y;\n    if (align & NK_TEXT_ALIGN_LEFT) {\n        icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);\n        icon.x = NK_MAX(icon.x, 0);\n    } else icon.x = bounds.x + 2 * style->padding.x;\n\n    icon.x += style->image_padding.x;\n    icon.y += style->image_padding.y;\n    icon.w -= 2 * style->image_padding.x;\n    icon.h -= 2 * style->image_padding.y;\n\n    /* draw selectable */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_selectable(out, *state, style, *value, &bounds, &icon, img, NK_SYMBOL_NONE, str, len, align, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return old_value != *value;\n}\nNK_LIB nk_bool\nnk_do_selectable_symbol(nk_flags *state, struct nk_command_buffer *out,\n    struct nk_rect bounds, const char *str, int len, nk_flags align, nk_bool *value,\n    enum nk_symbol_type sym, const struct nk_style_selectable *style,\n    const struct nk_input *in, const struct nk_user_font *font)\n{\n    int old_value;\n    struct nk_rect touch;\n    struct nk_rect icon;\n\n    NK_ASSERT(state);\n    NK_ASSERT(out);\n    NK_ASSERT(str);\n    NK_ASSERT(len);\n    NK_ASSERT(value);\n    NK_ASSERT(style);\n    NK_ASSERT(font);\n\n    if (!state || !out || !str || !len || !value || !style || !font) return 0;\n    old_value = *value;\n\n    /* toggle behavior */\n    touch.x = bounds.x - style->touch_padding.x;\n    touch.y = bounds.y - style->touch_padding.y;\n    touch.w = bounds.w + style->touch_padding.x * 2;\n    touch.h = bounds.h + style->touch_padding.y * 2;\n    if (nk_button_behavior(state, touch, in, NK_BUTTON_DEFAULT))\n        *value = !(*value);\n\n    icon.y = bounds.y + style->padding.y;\n    icon.w = icon.h = bounds.h - 2 * style->padding.y;\n    if (align & NK_TEXT_ALIGN_LEFT) {\n        icon.x = (bounds.x + bounds.w) - (2 * style->padding.x + icon.w);\n        icon.x = NK_MAX(icon.x, 0);\n    } else icon.x = bounds.x + 2 * style->padding.x;\n\n    icon.x += style->image_padding.x;\n    icon.y += style->image_padding.y;\n    icon.w -= 2 * style->image_padding.x;\n    icon.h -= 2 * style->image_padding.y;\n\n    /* draw selectable */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_selectable(out, *state, style, *value, &bounds, &icon, 0, sym, str, len, align, font);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return old_value != *value;\n}\n\nNK_API nk_bool\nnk_selectable_text(struct nk_context *ctx, const char *str, int len,\n    nk_flags align, nk_bool *value)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    enum nk_widget_layout_states state;\n    struct nk_rect bounds;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(value);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !value)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n    style = &ctx->style;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds,\n                str, len, align, value, &style->selectable, in, style->font);\n}\nNK_API nk_bool\nnk_selectable_image_text(struct nk_context *ctx, struct nk_image img,\n    const char *str, int len, nk_flags align, nk_bool *value)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    enum nk_widget_layout_states state;\n    struct nk_rect bounds;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(value);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !value)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n    style = &ctx->style;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_selectable_image(&ctx->last_widget_state, &win->buffer, bounds,\n                str, len, align, value, &img, &style->selectable, in, style->font);\n}\nNK_API nk_bool\nnk_selectable_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *str, int len, nk_flags align, nk_bool *value)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    enum nk_widget_layout_states state;\n    struct nk_rect bounds;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(value);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || !value)\n        return 0;\n\n    win = ctx->current;\n    layout = win->layout;\n    style = &ctx->style;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return 0;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    return nk_do_selectable_symbol(&ctx->last_widget_state, &win->buffer, bounds,\n                str, len, align, value, sym, &style->selectable, in, style->font);\n}\nNK_API nk_bool\nnk_selectable_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *title, nk_flags align, nk_bool *value)\n{\n    return nk_selectable_symbol_text(ctx, sym, title, nk_strlen(title), align, value);\n}\nNK_API nk_bool nk_select_text(struct nk_context *ctx, const char *str, int len,\n    nk_flags align, nk_bool value)\n{\n    nk_selectable_text(ctx, str, len, align, &value);return value;\n}\nNK_API nk_bool nk_selectable_label(struct nk_context *ctx, const char *str, nk_flags align, nk_bool *value)\n{\n    return nk_selectable_text(ctx, str, nk_strlen(str), align, value);\n}\nNK_API nk_bool nk_selectable_image_label(struct nk_context *ctx,struct nk_image img,\n    const char *str, nk_flags align, nk_bool *value)\n{\n    return nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, value);\n}\nNK_API nk_bool nk_select_label(struct nk_context *ctx, const char *str, nk_flags align, nk_bool value)\n{\n    nk_selectable_text(ctx, str, nk_strlen(str), align, &value);return value;\n}\nNK_API nk_bool nk_select_image_label(struct nk_context *ctx, struct nk_image img,\n    const char *str, nk_flags align, nk_bool value)\n{\n    nk_selectable_image_text(ctx, img, str, nk_strlen(str), align, &value);return value;\n}\nNK_API nk_bool nk_select_image_text(struct nk_context *ctx, struct nk_image img,\n    const char *str, int len, nk_flags align, nk_bool value)\n{\n    nk_selectable_image_text(ctx, img, str, len, align, &value);return value;\n}\nNK_API nk_bool\nnk_select_symbol_text(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *title, int title_len, nk_flags align, nk_bool value)\n{\n    nk_selectable_symbol_text(ctx, sym, title, title_len, align, &value);return value;\n}\nNK_API nk_bool\nnk_select_symbol_label(struct nk_context *ctx, enum nk_symbol_type sym,\n    const char *title, nk_flags align, nk_bool value)\n{\n    return nk_select_symbol_text(ctx, sym, title, nk_strlen(title), align, value);\n}\n\n"
  },
  {
    "path": "src/nuklear_slider.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              SLIDER\n *\n * ===============================================================*/\nNK_LIB float\nnk_slider_behavior(nk_flags *state, struct nk_rect *logical_cursor,\n    struct nk_rect *visual_cursor, struct nk_input *in,\n    struct nk_rect bounds, float slider_min, float slider_max, float slider_value,\n    float slider_step, float slider_steps)\n{\n    int left_mouse_down;\n    int left_mouse_click_in_cursor;\n\n    /* check if visual cursor is being dragged */\n    nk_widget_state_reset(state);\n    left_mouse_down = in && in->mouse.buttons[NK_BUTTON_LEFT].down;\n    left_mouse_click_in_cursor = in && nk_input_has_mouse_click_down_in_rect(in,\n            NK_BUTTON_LEFT, *visual_cursor, nk_true);\n\n    if (left_mouse_down && left_mouse_click_in_cursor) {\n        float ratio = 0;\n        const float d = in->mouse.pos.x - (visual_cursor->x+visual_cursor->w*0.5f);\n        const float pxstep = bounds.w / slider_steps;\n\n        /* only update value if the next slider step is reached */\n        *state = NK_WIDGET_STATE_ACTIVE;\n        if (NK_ABS(d) >= pxstep) {\n            const float steps = (float)((int)(NK_ABS(d) / pxstep));\n            slider_value += (d > 0) ? (slider_step*steps) : -(slider_step*steps);\n            slider_value = NK_CLAMP(slider_min, slider_value, slider_max);\n            ratio = (slider_value - slider_min)/slider_step;\n            logical_cursor->x = bounds.x + (logical_cursor->w * ratio);\n            in->mouse.buttons[NK_BUTTON_LEFT].clicked_pos.x = logical_cursor->x;\n        }\n    }\n\n    /* slider widget state */\n    if (nk_input_is_mouse_hovering_rect(in, bounds))\n        *state = NK_WIDGET_STATE_HOVERED;\n    if (*state & NK_WIDGET_STATE_HOVER &&\n        !nk_input_is_mouse_prev_hovering_rect(in, bounds))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, bounds))\n        *state |= NK_WIDGET_STATE_LEFT;\n    return slider_value;\n}\nNK_LIB void\nnk_draw_slider(struct nk_command_buffer *out, nk_flags state,\n    const struct nk_style_slider *style, const struct nk_rect *bounds,\n    const struct nk_rect *visual_cursor, float min, float value, float max)\n{\n    struct nk_rect fill;\n    struct nk_rect bar;\n    const struct nk_style_item *background;\n\n    /* select correct slider images/colors */\n    struct nk_color bar_color;\n    const struct nk_style_item *cursor;\n\n    NK_UNUSED(min);\n    NK_UNUSED(max);\n    NK_UNUSED(value);\n\n    if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->active;\n        bar_color = style->bar_active;\n        cursor = &style->cursor_active;\n    } else if (state & NK_WIDGET_STATE_HOVER) {\n        background = &style->hover;\n        bar_color = style->bar_hover;\n        cursor = &style->cursor_hover;\n    } else {\n        background = &style->normal;\n        bar_color = style->bar_normal;\n        cursor = &style->cursor_normal;\n    }\n\n    /* calculate slider background bar */\n    bar.x = bounds->x;\n    bar.y = (visual_cursor->y + visual_cursor->h/2) - bounds->h/12;\n    bar.w = bounds->w;\n    bar.h = bounds->h/6;\n\n    /* filled background bar style */\n    fill.w = (visual_cursor->x + (visual_cursor->w/2.0f)) - bar.x;\n    fill.x = bar.x;\n    fill.y = bar.y;\n    fill.h = bar.h;\n\n    /* draw background */\n    switch(background->type) {\n        case NK_STYLE_ITEM_IMAGE:\n            nk_draw_image(out, *bounds, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_NINE_SLICE:\n            nk_draw_nine_slice(out, *bounds, &background->data.slice, nk_rgb_factor(nk_white, style->color_factor));\n            break;\n        case NK_STYLE_ITEM_COLOR:\n            nk_fill_rect(out, *bounds, style->rounding, nk_rgb_factor(background->data.color, style->color_factor));\n            nk_stroke_rect(out, *bounds, style->rounding, style->border, nk_rgb_factor(style->border_color, style->color_factor));\n            break;\n    }\n\n    /* draw slider bar */\n    nk_fill_rect(out, bar, style->rounding, nk_rgb_factor(bar_color, style->color_factor));\n    nk_fill_rect(out, fill, style->rounding, nk_rgb_factor(style->bar_filled, style->color_factor));\n\n    /* draw cursor */\n    if (cursor->type == NK_STYLE_ITEM_IMAGE)\n        nk_draw_image(out, *visual_cursor, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));\n    else\n        nk_fill_circle(out, *visual_cursor, nk_rgb_factor(cursor->data.color, style->color_factor));\n}\nNK_LIB float\nnk_do_slider(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect bounds,\n    float min, float val, float max, float step,\n    const struct nk_style_slider *style, struct nk_input *in,\n    const struct nk_user_font *font)\n{\n    float slider_range;\n    float slider_min;\n    float slider_max;\n    float slider_value;\n    float slider_steps;\n    float cursor_offset;\n\n    struct nk_rect visual_cursor;\n    struct nk_rect logical_cursor;\n\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    if (!out || !style)\n        return 0;\n\n    /* remove padding from slider bounds */\n    bounds.x = bounds.x + style->padding.x;\n    bounds.y = bounds.y + style->padding.y;\n    bounds.h = NK_MAX(bounds.h, 2*style->padding.y);\n    bounds.w = NK_MAX(bounds.w, 2*style->padding.x + style->cursor_size.x);\n    bounds.w -= 2 * style->padding.x;\n    bounds.h -= 2 * style->padding.y;\n\n    /* optional buttons */\n    if (style->show_buttons) {\n        nk_flags ws;\n        struct nk_rect button;\n        button.y = bounds.y;\n        button.w = bounds.h;\n        button.h = bounds.h;\n\n        /* decrement button */\n        button.x = bounds.x;\n        if (nk_do_button_symbol(&ws, out, button, style->dec_symbol, NK_BUTTON_DEFAULT,\n            &style->dec_button, in, font))\n            val -= step;\n\n        /* increment button */\n        button.x = (bounds.x + bounds.w) - button.w;\n        if (nk_do_button_symbol(&ws, out, button, style->inc_symbol, NK_BUTTON_DEFAULT,\n            &style->inc_button, in, font))\n            val += step;\n\n        bounds.x = bounds.x + button.w + style->spacing.x;\n        bounds.w = bounds.w - (2*button.w + 2*style->spacing.x);\n    }\n\n    /* remove one cursor size to support visual cursor */\n    bounds.x += style->cursor_size.x*0.5f;\n    bounds.w -= style->cursor_size.x;\n\n    /* make sure the provided values are correct */\n    slider_max = NK_MAX(min, max);\n    slider_min = NK_MIN(min, max);\n    slider_value = NK_CLAMP(slider_min, val, slider_max);\n    slider_range = slider_max - slider_min;\n    slider_steps = slider_range / step;\n    cursor_offset = (slider_value - slider_min) / step;\n\n    /* calculate cursor\n    Basically you have two cursors. One for visual representation and interaction\n    and one for updating the actual cursor value. */\n    logical_cursor.h = bounds.h;\n    logical_cursor.w = bounds.w / slider_steps;\n    logical_cursor.x = bounds.x + (logical_cursor.w * cursor_offset);\n    logical_cursor.y = bounds.y;\n\n    visual_cursor.h = style->cursor_size.y;\n    visual_cursor.w = style->cursor_size.x;\n    visual_cursor.y = (bounds.y + bounds.h*0.5f) - visual_cursor.h*0.5f;\n    visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;\n\n    slider_value = nk_slider_behavior(state, &logical_cursor, &visual_cursor,\n        in, bounds, slider_min, slider_max, slider_value, step, slider_steps);\n    visual_cursor.x = logical_cursor.x - visual_cursor.w*0.5f;\n\n    /* draw slider */\n    if (style->draw_begin) style->draw_begin(out, style->userdata);\n    nk_draw_slider(out, *state, style, &bounds, &visual_cursor, slider_min, slider_value, slider_max);\n    if (style->draw_end) style->draw_end(out, style->userdata);\n    return slider_value;\n}\nNK_API nk_bool\nnk_slider_float(struct nk_context *ctx, float min_value, float *value, float max_value,\n    float value_step)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    struct nk_input *in;\n    const struct nk_style *style;\n\n    int ret = 0;\n    float old_value;\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    NK_ASSERT(value);\n    if (!ctx || !ctx->current || !ctx->current->layout || !value)\n        return ret;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return ret;\n    in = (/*state == NK_WIDGET_ROM || */ state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n\n    old_value = *value;\n    *value = nk_do_slider(&ctx->last_widget_state, &win->buffer, bounds, min_value,\n                old_value, max_value, value_step, &style->slider, in, style->font);\n    return (old_value > *value || old_value < *value);\n}\nNK_API float\nnk_slide_float(struct nk_context *ctx, float min, float val, float max, float step)\n{\n    nk_slider_float(ctx, min, &val, max, step); return val;\n}\nNK_API int\nnk_slide_int(struct nk_context *ctx, int min, int val, int max, int step)\n{\n    float value = (float)val;\n    nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);\n    return (int)value;\n}\nNK_API nk_bool\nnk_slider_int(struct nk_context *ctx, int min, int *val, int max, int step)\n{\n    int ret;\n    float value = (float)*val;\n    ret = nk_slider_float(ctx, (float)min, &value, (float)max, (float)step);\n    *val =  (int)value;\n    return ret;\n}\n\n"
  },
  {
    "path": "src/nuklear_string.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              STRING\n *\n * ===============================================================*/\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void\nnk_str_init_default(struct nk_str *str)\n{\n    struct nk_allocator alloc;\n    alloc.userdata.ptr = 0;\n    alloc.alloc = nk_malloc;\n    alloc.free = nk_mfree;\n    nk_buffer_init(&str->buffer, &alloc, 32);\n    str->len = 0;\n}\n#endif\n\nNK_API void\nnk_str_init(struct nk_str *str, const struct nk_allocator *alloc, nk_size size)\n{\n    nk_buffer_init(&str->buffer, alloc, size);\n    str->len = 0;\n}\nNK_API void\nnk_str_init_fixed(struct nk_str *str, void *memory, nk_size size)\n{\n    nk_buffer_init_fixed(&str->buffer, memory, size);\n    str->len = 0;\n}\nNK_API int\nnk_str_append_text_char(struct nk_str *s, const char *str, int len)\n{\n    char *mem;\n    NK_ASSERT(s);\n    NK_ASSERT(str);\n    if (!s || !str || !len) return 0;\n    mem = (char*)nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0);\n    if (!mem) return 0;\n    NK_MEMCPY(mem, str, (nk_size)len * sizeof(char));\n    s->len += nk_utf_len(str, len);\n    return len;\n}\nNK_API int\nnk_str_append_str_char(struct nk_str *s, const char *str)\n{\n    return nk_str_append_text_char(s, str, nk_strlen(str));\n}\nNK_API int\nnk_str_append_text_utf8(struct nk_str *str, const char *text, int len)\n{\n    int i = 0;\n    int byte_len = 0;\n    nk_rune unicode;\n    if (!str || !text || !len) return 0;\n    for (i = 0; i < len; ++i)\n        byte_len += nk_utf_decode(text+byte_len, &unicode, 4);\n    nk_str_append_text_char(str, text, byte_len);\n    return len;\n}\nNK_API int\nnk_str_append_str_utf8(struct nk_str *str, const char *text)\n{\n    int byte_len = 0;\n    int num_runes = 0;\n    int glyph_len = 0;\n    nk_rune unicode;\n    if (!str || !text) return 0;\n\n    glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4);\n    while (unicode != '\\0' && glyph_len) {\n        glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);\n        byte_len += glyph_len;\n        num_runes++;\n    }\n    nk_str_append_text_char(str, text, byte_len);\n    return num_runes;\n}\nNK_API int\nnk_str_append_text_runes(struct nk_str *str, const nk_rune *text, int len)\n{\n    int i = 0;\n    int byte_len = 0;\n    nk_glyph glyph;\n\n    NK_ASSERT(str);\n    if (!str || !text || !len) return 0;\n    for (i = 0; i < len; ++i) {\n        byte_len = nk_utf_encode(text[i], glyph, NK_UTF_SIZE);\n        if (!byte_len) break;\n        nk_str_append_text_char(str, glyph, byte_len);\n    }\n    return len;\n}\nNK_API int\nnk_str_append_str_runes(struct nk_str *str, const nk_rune *runes)\n{\n    int i = 0;\n    nk_glyph glyph;\n    int byte_len;\n    NK_ASSERT(str);\n    if (!str || !runes) return 0;\n    while (runes[i] != '\\0') {\n        byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);\n        nk_str_append_text_char(str, glyph, byte_len);\n        i++;\n    }\n    return i;\n}\nNK_API int\nnk_str_insert_at_char(struct nk_str *s, int pos, const char *str, int len)\n{\n    int i;\n    void *mem;\n    char *src;\n    char *dst;\n\n    int copylen;\n    NK_ASSERT(s);\n    NK_ASSERT(str);\n    NK_ASSERT(len >= 0);\n    if (!s || !str || !len || (nk_size)pos > s->buffer.allocated) return 0;\n    if ((s->buffer.allocated + (nk_size)len >= s->buffer.memory.size) &&\n        (s->buffer.type == NK_BUFFER_FIXED)) return 0;\n\n    copylen = (int)s->buffer.allocated - pos;\n    if (!copylen) {\n        nk_str_append_text_char(s, str, len);\n        return 1;\n    }\n    mem = nk_buffer_alloc(&s->buffer, NK_BUFFER_FRONT, (nk_size)len * sizeof(char), 0);\n    if (!mem) return 0;\n\n    /* memmove */\n    NK_ASSERT(((int)pos + (int)len + ((int)copylen - 1)) >= 0);\n    NK_ASSERT(((int)pos + ((int)copylen - 1)) >= 0);\n    dst = nk_ptr_add(char, s->buffer.memory.ptr, pos + len + (copylen - 1));\n    src = nk_ptr_add(char, s->buffer.memory.ptr, pos + (copylen-1));\n    for (i = 0; i < copylen; ++i) *dst-- = *src--;\n    mem = nk_ptr_add(void, s->buffer.memory.ptr, pos);\n    NK_MEMCPY(mem, str, (nk_size)len * sizeof(char));\n    s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);\n    return 1;\n}\nNK_API int\nnk_str_insert_at_rune(struct nk_str *str, int pos, const char *cstr, int len)\n{\n    int glyph_len;\n    nk_rune unicode;\n    const char *begin;\n    const char *buffer;\n\n    NK_ASSERT(str);\n    NK_ASSERT(cstr);\n    NK_ASSERT(len);\n    if (!str || !cstr || !len) return 0;\n    begin = nk_str_at_rune(str, pos, &unicode, &glyph_len);\n    if (!str->len)\n        return nk_str_append_text_char(str, cstr, len);\n    buffer = nk_str_get_const(str);\n    if (!begin) return 0;\n    return nk_str_insert_at_char(str, (int)(begin - buffer), cstr, len);\n}\nNK_API int\nnk_str_insert_text_char(struct nk_str *str, int pos, const char *text, int len)\n{\n    return nk_str_insert_text_utf8(str, pos, text, len);\n}\nNK_API int\nnk_str_insert_str_char(struct nk_str *str, int pos, const char *text)\n{\n    return nk_str_insert_text_utf8(str, pos, text, nk_strlen(text));\n}\nNK_API int\nnk_str_insert_text_utf8(struct nk_str *str, int pos, const char *text, int len)\n{\n    int i = 0;\n    int byte_len = 0;\n    nk_rune unicode;\n\n    NK_ASSERT(str);\n    NK_ASSERT(text);\n    if (!str || !text || !len) return 0;\n    for (i = 0; i < len; ++i)\n        byte_len += nk_utf_decode(text+byte_len, &unicode, 4);\n    nk_str_insert_at_rune(str, pos, text, byte_len);\n    return len;\n}\nNK_API int\nnk_str_insert_str_utf8(struct nk_str *str, int pos, const char *text)\n{\n    int byte_len = 0;\n    int num_runes = 0;\n    int glyph_len = 0;\n    nk_rune unicode;\n    if (!str || !text) return 0;\n\n    glyph_len = byte_len = nk_utf_decode(text+byte_len, &unicode, 4);\n    while (unicode != '\\0' && glyph_len) {\n        glyph_len = nk_utf_decode(text+byte_len, &unicode, 4);\n        byte_len += glyph_len;\n        num_runes++;\n    }\n    nk_str_insert_at_rune(str, pos, text, byte_len);\n    return num_runes;\n}\nNK_API int\nnk_str_insert_text_runes(struct nk_str *str, int pos, const nk_rune *runes, int len)\n{\n    int i = 0;\n    int byte_len = 0;\n    nk_glyph glyph;\n\n    NK_ASSERT(str);\n    if (!str || !runes || !len) return 0;\n    for (i = 0; i < len; ++i) {\n        byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);\n        if (!byte_len) break;\n        nk_str_insert_at_rune(str, pos+i, glyph, byte_len);\n    }\n    return len;\n}\nNK_API int\nnk_str_insert_str_runes(struct nk_str *str, int pos, const nk_rune *runes)\n{\n    int i = 0;\n    nk_glyph glyph;\n    int byte_len;\n    NK_ASSERT(str);\n    if (!str || !runes) return 0;\n    while (runes[i] != '\\0') {\n        byte_len = nk_utf_encode(runes[i], glyph, NK_UTF_SIZE);\n        nk_str_insert_at_rune(str, pos+i, glyph, byte_len);\n        i++;\n    }\n    return i;\n}\nNK_API void\nnk_str_remove_chars(struct nk_str *s, int len)\n{\n    NK_ASSERT(s);\n    NK_ASSERT(len >= 0);\n    if (!s || len < 0 || (nk_size)len > s->buffer.allocated) return;\n    NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0);\n    s->buffer.allocated -= (nk_size)len;\n    s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);\n}\nNK_API void\nnk_str_remove_runes(struct nk_str *str, int len)\n{\n    int index;\n    const char *begin;\n    const char *end;\n    nk_rune unicode;\n\n    NK_ASSERT(str);\n    NK_ASSERT(len >= 0);\n    if (!str || len < 0) return;\n    if (len >= str->len) {\n        str->len = 0;\n        return;\n    }\n\n    index = str->len - len;\n    begin = nk_str_at_rune(str, index, &unicode, &len);\n    end = (const char*)str->buffer.memory.ptr + str->buffer.allocated;\n    nk_str_remove_chars(str, (int)(end-begin)+1);\n}\nNK_API void\nnk_str_delete_chars(struct nk_str *s, int pos, int len)\n{\n    NK_ASSERT(s);\n    if (!s || !len || (nk_size)pos > s->buffer.allocated ||\n        (nk_size)(pos + len) > s->buffer.allocated) return;\n\n    if ((nk_size)(pos + len) < s->buffer.allocated) {\n        /* memmove */\n        char *dst = nk_ptr_add(char, s->buffer.memory.ptr, pos);\n        char *src = nk_ptr_add(char, s->buffer.memory.ptr, pos + len);\n        NK_MEMCPY(dst, src, s->buffer.allocated - (nk_size)(pos + len));\n        NK_ASSERT(((int)s->buffer.allocated - (int)len) >= 0);\n        s->buffer.allocated -= (nk_size)len;\n    } else nk_str_remove_chars(s, len);\n    s->len = nk_utf_len((char *)s->buffer.memory.ptr, (int)s->buffer.allocated);\n}\nNK_API void\nnk_str_delete_runes(struct nk_str *s, int pos, int len)\n{\n    char *temp;\n    nk_rune unicode;\n    char *begin;\n    char *end;\n    int unused;\n\n    NK_ASSERT(s);\n    NK_ASSERT(s->len >= pos + len);\n    if (s->len < pos + len)\n        len = NK_CLAMP(0, (s->len - pos), s->len);\n    if (!len) return;\n\n    temp = (char *)s->buffer.memory.ptr;\n    begin = nk_str_at_rune(s, pos, &unicode, &unused);\n    if (!begin) return;\n    s->buffer.memory.ptr = begin;\n    end = nk_str_at_rune(s, len, &unicode, &unused);\n    s->buffer.memory.ptr = temp;\n    if (!end) return;\n    nk_str_delete_chars(s, (int)(begin - temp), (int)(end - begin));\n}\nNK_API char*\nnk_str_at_char(struct nk_str *s, int pos)\n{\n    NK_ASSERT(s);\n    if (!s || pos > (int)s->buffer.allocated) return 0;\n    return nk_ptr_add(char, s->buffer.memory.ptr, pos);\n}\nNK_API char*\nnk_str_at_rune(struct nk_str *str, int pos, nk_rune *unicode, int *len)\n{\n    int i = 0;\n    int src_len = 0;\n    int glyph_len = 0;\n    char *text;\n    int text_len;\n\n    NK_ASSERT(str);\n    NK_ASSERT(unicode);\n    NK_ASSERT(len);\n\n    if (!str || !unicode || !len) return 0;\n    if (pos < 0) {\n        *unicode = 0;\n        *len = 0;\n        return 0;\n    }\n\n    text = (char*)str->buffer.memory.ptr;\n    text_len = (int)str->buffer.allocated;\n    glyph_len = nk_utf_decode(text, unicode, text_len);\n    while (glyph_len) {\n        if (i == pos) {\n            *len = glyph_len;\n            break;\n        }\n\n        i++;\n        src_len = src_len + glyph_len;\n        glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);\n    }\n    if (i != pos) return 0;\n    return text + src_len;\n}\nNK_API const char*\nnk_str_at_char_const(const struct nk_str *s, int pos)\n{\n    NK_ASSERT(s);\n    if (!s || pos > (int)s->buffer.allocated) return 0;\n    return nk_ptr_add(char, s->buffer.memory.ptr, pos);\n}\nNK_API const char*\nnk_str_at_const(const struct nk_str *str, int pos, nk_rune *unicode, int *len)\n{\n    int i = 0;\n    int src_len = 0;\n    int glyph_len = 0;\n    char *text;\n    int text_len;\n\n    NK_ASSERT(str);\n    NK_ASSERT(unicode);\n    NK_ASSERT(len);\n\n    if (!str || !unicode || !len) return 0;\n    if (pos < 0) {\n        *unicode = 0;\n        *len = 0;\n        return 0;\n    }\n\n    text = (char*)str->buffer.memory.ptr;\n    text_len = (int)str->buffer.allocated;\n    glyph_len = nk_utf_decode(text, unicode, text_len);\n    while (glyph_len) {\n        if (i == pos) {\n            *len = glyph_len;\n            break;\n        }\n\n        i++;\n        src_len = src_len + glyph_len;\n        glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);\n    }\n    if (i != pos) return 0;\n    return text + src_len;\n}\nNK_API nk_rune\nnk_str_rune_at(const struct nk_str *str, int pos)\n{\n    int len;\n    nk_rune unicode = 0;\n    nk_str_at_const(str, pos, &unicode, &len);\n    return unicode;\n}\nNK_API char*\nnk_str_get(struct nk_str *s)\n{\n    NK_ASSERT(s);\n    if (!s || !s->len || !s->buffer.allocated) return 0;\n    return (char*)s->buffer.memory.ptr;\n}\nNK_API const char*\nnk_str_get_const(const struct nk_str *s)\n{\n    NK_ASSERT(s);\n    if (!s || !s->len || !s->buffer.allocated) return 0;\n    return (const char*)s->buffer.memory.ptr;\n}\nNK_API int\nnk_str_len(const struct nk_str *s)\n{\n    NK_ASSERT(s);\n    if (!s || !s->len || !s->buffer.allocated) return 0;\n    return s->len;\n}\nNK_API int\nnk_str_len_char(const struct nk_str *s)\n{\n    NK_ASSERT(s);\n    if (!s || !s->len || !s->buffer.allocated) return 0;\n    return (int)s->buffer.allocated;\n}\nNK_API void\nnk_str_clear(struct nk_str *str)\n{\n    NK_ASSERT(str);\n    nk_buffer_clear(&str->buffer);\n    str->len = 0;\n}\nNK_API void\nnk_str_free(struct nk_str *str)\n{\n    NK_ASSERT(str);\n    nk_buffer_free(&str->buffer);\n    str->len = 0;\n}\n"
  },
  {
    "path": "src/nuklear_style.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              STYLE\n *\n * ===============================================================*/\nNK_API void nk_style_default(struct nk_context *ctx){nk_style_from_table(ctx, 0);}\n#define NK_COLOR_MAP(NK_COLOR)\\\n    NK_COLOR(NK_COLOR_TEXT,                     175,175,175,255) \\\n    NK_COLOR(NK_COLOR_WINDOW,                   45, 45, 45, 255) \\\n    NK_COLOR(NK_COLOR_HEADER,                   40, 40, 40, 255) \\\n    NK_COLOR(NK_COLOR_BORDER,                   65, 65, 65, 255) \\\n    NK_COLOR(NK_COLOR_BUTTON,                   50, 50, 50, 255) \\\n    NK_COLOR(NK_COLOR_BUTTON_HOVER,             40, 40, 40, 255) \\\n    NK_COLOR(NK_COLOR_BUTTON_ACTIVE,            35, 35, 35, 255) \\\n    NK_COLOR(NK_COLOR_TOGGLE,                   100,100,100,255) \\\n    NK_COLOR(NK_COLOR_TOGGLE_HOVER,             120,120,120,255) \\\n    NK_COLOR(NK_COLOR_TOGGLE_CURSOR,            45, 45, 45, 255) \\\n    NK_COLOR(NK_COLOR_SELECT,                   45, 45, 45, 255) \\\n    NK_COLOR(NK_COLOR_SELECT_ACTIVE,            35, 35, 35,255)  \\\n    NK_COLOR(NK_COLOR_SLIDER,                   38, 38, 38, 255) \\\n    NK_COLOR(NK_COLOR_SLIDER_CURSOR,            100,100,100,255) \\\n    NK_COLOR(NK_COLOR_SLIDER_CURSOR_HOVER,      120,120,120,255) \\\n    NK_COLOR(NK_COLOR_SLIDER_CURSOR_ACTIVE,     150,150,150,255) \\\n    NK_COLOR(NK_COLOR_PROPERTY,                 38, 38, 38, 255) \\\n    NK_COLOR(NK_COLOR_EDIT,                     38, 38, 38, 255) \\\n    NK_COLOR(NK_COLOR_EDIT_CURSOR,              175,175,175,255) \\\n    NK_COLOR(NK_COLOR_COMBO,                    45, 45, 45, 255) \\\n    NK_COLOR(NK_COLOR_CHART,                    120,120,120,255) \\\n    NK_COLOR(NK_COLOR_CHART_COLOR,              45, 45, 45, 255) \\\n    NK_COLOR(NK_COLOR_CHART_COLOR_HIGHLIGHT,    255, 0,  0, 255) \\\n    NK_COLOR(NK_COLOR_SCROLLBAR,                40, 40, 40, 255) \\\n    NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR,         100,100,100,255) \\\n    NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_HOVER,   120,120,120,255) \\\n    NK_COLOR(NK_COLOR_SCROLLBAR_CURSOR_ACTIVE,  150,150,150,255) \\\n    NK_COLOR(NK_COLOR_TAB_HEADER,               40, 40, 40,255)  \\\n    NK_COLOR(NK_COLOR_KNOB,                     38, 38, 38, 255) \\\n    NK_COLOR(NK_COLOR_KNOB_CURSOR,              100,100,100,255) \\\n    NK_COLOR(NK_COLOR_KNOB_CURSOR_HOVER,        120,120,120,255) \\\n    NK_COLOR(NK_COLOR_KNOB_CURSOR_ACTIVE,       150,150,150,255)\n\nNK_GLOBAL const struct nk_color\nnk_default_color_style[NK_COLOR_COUNT] = {\n#define NK_COLOR(a,b,c,d,e) {b,c,d,e},\n    NK_COLOR_MAP(NK_COLOR)\n#undef NK_COLOR\n};\nNK_GLOBAL const char *nk_color_names[NK_COLOR_COUNT] = {\n#define NK_COLOR(a,b,c,d,e) #a,\n    NK_COLOR_MAP(NK_COLOR)\n#undef NK_COLOR\n};\n\nNK_API const char*\nnk_style_get_color_by_name(enum nk_style_colors c)\n{\n    return nk_color_names[c];\n}\nNK_API struct nk_style_item\nnk_style_item_color(struct nk_color col)\n{\n    struct nk_style_item i;\n    i.type = NK_STYLE_ITEM_COLOR;\n    i.data.color = col;\n    return i;\n}\nNK_API struct nk_style_item\nnk_style_item_image(struct nk_image img)\n{\n    struct nk_style_item i;\n    i.type = NK_STYLE_ITEM_IMAGE;\n    i.data.image = img;\n    return i;\n}\nNK_API struct nk_style_item\nnk_style_item_nine_slice(struct nk_nine_slice slice)\n{\n    struct nk_style_item i;\n    i.type = NK_STYLE_ITEM_NINE_SLICE;\n    i.data.slice = slice;\n    return i;\n}\nNK_API struct nk_style_item\nnk_style_item_hide(void)\n{\n    struct nk_style_item i;\n    i.type = NK_STYLE_ITEM_COLOR;\n    i.data.color = nk_rgba(0,0,0,0);\n    return i;\n}\nNK_API void\nnk_style_from_table(struct nk_context *ctx, const struct nk_color *table)\n{\n    struct nk_style *style;\n    struct nk_style_text *text;\n    struct nk_style_button *button;\n    struct nk_style_toggle *toggle;\n    struct nk_style_selectable *select;\n    struct nk_style_slider *slider;\n    struct nk_style_knob *knob;\n    struct nk_style_progress *prog;\n    struct nk_style_scrollbar *scroll;\n    struct nk_style_edit *edit;\n    struct nk_style_property *property;\n    struct nk_style_combo *combo;\n    struct nk_style_chart *chart;\n    struct nk_style_tab *tab;\n    struct nk_style_window *win;\n\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    style = &ctx->style;\n    table = (!table) ? nk_default_color_style: table;\n\n    /* default text */\n    text = &style->text;\n    text->color = table[NK_COLOR_TEXT];\n    text->padding = nk_vec2(0,0);\n    text->color_factor = 1.0f;\n    text->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n\n    /* default button */\n    button = &style->button;\n    nk_zero_struct(*button);\n    button->normal                     = nk_style_item_color(table[NK_COLOR_BUTTON]);\n    button->hover                      = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]);\n    button->active                     = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]);\n    button->border_color               = table[NK_COLOR_BORDER];\n    button->text_background            = table[NK_COLOR_BUTTON];\n    button->text_normal                = table[NK_COLOR_TEXT];\n    button->text_hover                 = table[NK_COLOR_TEXT];\n    button->text_active                = table[NK_COLOR_TEXT];\n    button->padding                    = nk_vec2(2.0f,2.0f);\n    button->image_padding              = nk_vec2(0.0f,0.0f);\n    button->touch_padding              = nk_vec2(0.0f, 0.0f);\n    button->userdata                   = nk_handle_ptr(0);\n    button->text_alignment             = NK_TEXT_CENTERED;\n    button->border                     = 1.0f;\n    button->rounding                   = 4.0f;\n    button->color_factor_text          = 1.0f;\n    button->color_factor_background    = 1.0f;\n    button->disabled_factor            = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin                 = 0;\n    button->draw_end                   = 0;\n\n    /* contextual button */\n    button = &style->contextual_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_BUTTON_HOVER]);\n    button->active          = nk_style_item_color(table[NK_COLOR_BUTTON_ACTIVE]);\n    button->border_color    = table[NK_COLOR_WINDOW];\n    button->text_background = table[NK_COLOR_WINDOW];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(2.0f,2.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n\n    /* menu button */\n    button = &style->menu_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->active          = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->border_color    = table[NK_COLOR_WINDOW];\n    button->text_background = table[NK_COLOR_WINDOW];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(2.0f,2.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 1.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n\n    /* checkbox toggle */\n    toggle = &style->checkbox;\n    nk_zero_struct(*toggle);\n    toggle->normal          = nk_style_item_color(table[NK_COLOR_TOGGLE]);\n    toggle->hover           = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);\n    toggle->active          = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);\n    toggle->cursor_normal   = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);\n    toggle->cursor_hover    = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);\n    toggle->userdata        = nk_handle_ptr(0);\n    toggle->text_background = table[NK_COLOR_WINDOW];\n    toggle->text_normal     = table[NK_COLOR_TEXT];\n    toggle->text_hover      = table[NK_COLOR_TEXT];\n    toggle->text_active     = table[NK_COLOR_TEXT];\n    toggle->padding         = nk_vec2(2.0f, 2.0f);\n    toggle->touch_padding   = nk_vec2(0,0);\n    toggle->border_color    = nk_rgba(0,0,0,0);\n    toggle->border          = 0.0f;\n    toggle->spacing         = 4;\n    toggle->color_factor    = 1.0f;\n    toggle->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n\n    /* option toggle */\n    toggle = &style->option;\n    nk_zero_struct(*toggle);\n    toggle->normal          = nk_style_item_color(table[NK_COLOR_TOGGLE]);\n    toggle->hover           = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);\n    toggle->active          = nk_style_item_color(table[NK_COLOR_TOGGLE_HOVER]);\n    toggle->cursor_normal   = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);\n    toggle->cursor_hover    = nk_style_item_color(table[NK_COLOR_TOGGLE_CURSOR]);\n    toggle->userdata        = nk_handle_ptr(0);\n    toggle->text_background = table[NK_COLOR_WINDOW];\n    toggle->text_normal     = table[NK_COLOR_TEXT];\n    toggle->text_hover      = table[NK_COLOR_TEXT];\n    toggle->text_active     = table[NK_COLOR_TEXT];\n    toggle->padding         = nk_vec2(3.0f, 3.0f);\n    toggle->touch_padding   = nk_vec2(0,0);\n    toggle->border_color    = nk_rgba(0,0,0,0);\n    toggle->border          = 0.0f;\n    toggle->spacing         = 4;\n    toggle->color_factor    = 1.0f;\n    toggle->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n\n    /* selectable */\n    select = &style->selectable;\n    nk_zero_struct(*select);\n    select->normal          = nk_style_item_color(table[NK_COLOR_SELECT]);\n    select->hover           = nk_style_item_color(table[NK_COLOR_SELECT]);\n    select->pressed         = nk_style_item_color(table[NK_COLOR_SELECT]);\n    select->normal_active   = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);\n    select->hover_active    = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);\n    select->pressed_active  = nk_style_item_color(table[NK_COLOR_SELECT_ACTIVE]);\n    select->text_normal     = table[NK_COLOR_TEXT];\n    select->text_hover      = table[NK_COLOR_TEXT];\n    select->text_pressed    = table[NK_COLOR_TEXT];\n    select->text_normal_active  = table[NK_COLOR_TEXT];\n    select->text_hover_active   = table[NK_COLOR_TEXT];\n    select->text_pressed_active = table[NK_COLOR_TEXT];\n    select->padding         = nk_vec2(2.0f,2.0f);\n    select->image_padding   = nk_vec2(2.0f,2.0f);\n    select->touch_padding   = nk_vec2(0,0);\n    select->userdata        = nk_handle_ptr(0);\n    select->rounding        = 0.0f;\n    select->color_factor    = 1.0f;\n    select->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    select->draw_begin      = 0;\n    select->draw_end        = 0;\n\n    /* slider */\n    slider = &style->slider;\n    nk_zero_struct(*slider);\n    slider->normal          = nk_style_item_hide();\n    slider->hover           = nk_style_item_hide();\n    slider->active          = nk_style_item_hide();\n    slider->bar_normal      = table[NK_COLOR_SLIDER];\n    slider->bar_hover       = table[NK_COLOR_SLIDER];\n    slider->bar_active      = table[NK_COLOR_SLIDER];\n    slider->bar_filled      = table[NK_COLOR_SLIDER_CURSOR];\n    slider->cursor_normal   = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]);\n    slider->cursor_hover    = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]);\n    slider->cursor_active   = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]);\n    slider->inc_symbol      = NK_SYMBOL_TRIANGLE_RIGHT;\n    slider->dec_symbol      = NK_SYMBOL_TRIANGLE_LEFT;\n    slider->cursor_size     = nk_vec2(16,16);\n    slider->padding         = nk_vec2(2,2);\n    slider->spacing         = nk_vec2(2,2);\n    slider->userdata        = nk_handle_ptr(0);\n    slider->show_buttons    = nk_false;\n    slider->bar_height      = 8;\n    slider->rounding        = 0;\n    slider->color_factor    = 1.0f;\n    slider->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    slider->draw_begin      = 0;\n    slider->draw_end        = 0;\n\n    /* slider buttons */\n    button = &style->slider.inc_button;\n    button->normal          = nk_style_item_color(nk_rgb(40,40,40));\n    button->hover           = nk_style_item_color(nk_rgb(42,42,42));\n    button->active          = nk_style_item_color(nk_rgb(44,44,44));\n    button->border_color    = nk_rgb(65,65,65);\n    button->text_background = nk_rgb(40,40,40);\n    button->text_normal     = nk_rgb(175,175,175);\n    button->text_hover      = nk_rgb(175,175,175);\n    button->text_active     = nk_rgb(175,175,175);\n    button->padding         = nk_vec2(8.0f,8.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 1.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n    style->slider.dec_button = style->slider.inc_button;\n\n    /* knob */\n    knob = &style->knob;\n    nk_zero_struct(*knob);\n    knob->normal          = nk_style_item_hide();\n    knob->hover           = nk_style_item_hide();\n    knob->active          = nk_style_item_hide();\n    knob->knob_normal     = table[NK_COLOR_KNOB];\n    knob->knob_hover      = table[NK_COLOR_KNOB];\n    knob->knob_active     = table[NK_COLOR_KNOB];\n    knob->cursor_normal   = table[NK_COLOR_KNOB_CURSOR];\n    knob->cursor_hover    = table[NK_COLOR_KNOB_CURSOR_HOVER];\n    knob->cursor_active   = table[NK_COLOR_KNOB_CURSOR_ACTIVE];\n\n    knob->knob_border_color = table[NK_COLOR_BORDER];\n    knob->knob_border       = 1.0f;\n\n    knob->padding         = nk_vec2(2,2);\n    knob->spacing         = nk_vec2(2,2);\n    knob->cursor_width    = 2;\n    knob->color_factor    = 1.0f;\n    knob->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n\n    knob->userdata        = nk_handle_ptr(0);\n    knob->draw_begin      = 0;\n    knob->draw_end        = 0;\n\n    /* progressbar */\n    prog = &style->progress;\n    nk_zero_struct(*prog);\n    prog->normal            = nk_style_item_color(table[NK_COLOR_SLIDER]);\n    prog->hover             = nk_style_item_color(table[NK_COLOR_SLIDER]);\n    prog->active            = nk_style_item_color(table[NK_COLOR_SLIDER]);\n    prog->cursor_normal     = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR]);\n    prog->cursor_hover      = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_HOVER]);\n    prog->cursor_active     = nk_style_item_color(table[NK_COLOR_SLIDER_CURSOR_ACTIVE]);\n    prog->border_color      = nk_rgba(0,0,0,0);\n    prog->cursor_border_color = nk_rgba(0,0,0,0);\n    prog->userdata          = nk_handle_ptr(0);\n    prog->padding           = nk_vec2(4,4);\n    prog->rounding          = 0;\n    prog->border            = 0;\n    prog->cursor_rounding   = 0;\n    prog->cursor_border     = 0;\n    prog->color_factor      = 1.0f;\n    prog->disabled_factor   = NK_WIDGET_DISABLED_FACTOR;\n    prog->draw_begin        = 0;\n    prog->draw_end          = 0;\n\n    /* scrollbars */\n    scroll = &style->scrollh;\n    nk_zero_struct(*scroll);\n    scroll->normal          = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);\n    scroll->hover           = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);\n    scroll->active          = nk_style_item_color(table[NK_COLOR_SCROLLBAR]);\n    scroll->cursor_normal   = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR]);\n    scroll->cursor_hover    = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_HOVER]);\n    scroll->cursor_active   = nk_style_item_color(table[NK_COLOR_SCROLLBAR_CURSOR_ACTIVE]);\n    scroll->dec_symbol      = NK_SYMBOL_CIRCLE_SOLID;\n    scroll->inc_symbol      = NK_SYMBOL_CIRCLE_SOLID;\n    scroll->userdata        = nk_handle_ptr(0);\n    scroll->border_color    = table[NK_COLOR_SCROLLBAR];\n    scroll->cursor_border_color = table[NK_COLOR_SCROLLBAR];\n    scroll->padding         = nk_vec2(0,0);\n    scroll->show_buttons    = nk_false;\n    scroll->border          = 0;\n    scroll->rounding        = 0;\n    scroll->border_cursor   = 0;\n    scroll->rounding_cursor = 0;\n    scroll->color_factor    = 1.0f;\n    scroll->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    scroll->draw_begin      = 0;\n    scroll->draw_end        = 0;\n    style->scrollv = style->scrollh;\n\n    /* scrollbars buttons */\n    button = &style->scrollh.inc_button;\n    button->normal          = nk_style_item_color(nk_rgb(40,40,40));\n    button->hover           = nk_style_item_color(nk_rgb(42,42,42));\n    button->active          = nk_style_item_color(nk_rgb(44,44,44));\n    button->border_color    = nk_rgb(65,65,65);\n    button->text_background = nk_rgb(40,40,40);\n    button->text_normal     = nk_rgb(175,175,175);\n    button->text_hover      = nk_rgb(175,175,175);\n    button->text_active     = nk_rgb(175,175,175);\n    button->padding         = nk_vec2(4.0f,4.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 1.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n    style->scrollh.dec_button = style->scrollh.inc_button;\n    style->scrollv.inc_button = style->scrollh.inc_button;\n    style->scrollv.dec_button = style->scrollh.inc_button;\n\n    /* edit */\n    edit = &style->edit;\n    nk_zero_struct(*edit);\n    edit->normal            = nk_style_item_color(table[NK_COLOR_EDIT]);\n    edit->hover             = nk_style_item_color(table[NK_COLOR_EDIT]);\n    edit->active            = nk_style_item_color(table[NK_COLOR_EDIT]);\n    edit->cursor_normal     = table[NK_COLOR_TEXT];\n    edit->cursor_hover      = table[NK_COLOR_TEXT];\n    edit->cursor_text_normal= table[NK_COLOR_EDIT];\n    edit->cursor_text_hover = table[NK_COLOR_EDIT];\n    edit->border_color      = table[NK_COLOR_BORDER];\n    edit->text_normal       = table[NK_COLOR_TEXT];\n    edit->text_hover        = table[NK_COLOR_TEXT];\n    edit->text_active       = table[NK_COLOR_TEXT];\n    edit->selected_normal   = table[NK_COLOR_TEXT];\n    edit->selected_hover    = table[NK_COLOR_TEXT];\n    edit->selected_text_normal  = table[NK_COLOR_EDIT];\n    edit->selected_text_hover   = table[NK_COLOR_EDIT];\n    edit->scrollbar_size    = nk_vec2(10,10);\n    edit->scrollbar         = style->scrollv;\n    edit->padding           = nk_vec2(4,4);\n    edit->row_padding       = 2;\n    edit->cursor_size       = 4;\n    edit->border            = 1;\n    edit->rounding          = 0;\n    edit->color_factor      = 1.0f;\n    edit->disabled_factor   = NK_WIDGET_DISABLED_FACTOR;\n\n    /* property */\n    property = &style->property;\n    nk_zero_struct(*property);\n    property->normal        = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    property->hover         = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    property->active        = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    property->border_color  = table[NK_COLOR_BORDER];\n    property->label_normal  = table[NK_COLOR_TEXT];\n    property->label_hover   = table[NK_COLOR_TEXT];\n    property->label_active  = table[NK_COLOR_TEXT];\n    property->sym_left      = NK_SYMBOL_TRIANGLE_LEFT;\n    property->sym_right     = NK_SYMBOL_TRIANGLE_RIGHT;\n    property->userdata      = nk_handle_ptr(0);\n    property->padding       = nk_vec2(4,4);\n    property->border        = 1;\n    property->rounding      = 10;\n    property->draw_begin    = 0;\n    property->draw_end      = 0;\n    property->color_factor  = 1.0f;\n    property->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n\n    /* property buttons */\n    button = &style->property.dec_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    button->active          = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    button->border_color    = nk_rgba(0,0,0,0);\n    button->text_background = table[NK_COLOR_PROPERTY];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(0.0f,0.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n    style->property.inc_button = style->property.dec_button;\n\n    /* property edit */\n    edit = &style->property.edit;\n    nk_zero_struct(*edit);\n    edit->normal            = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    edit->hover             = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    edit->active            = nk_style_item_color(table[NK_COLOR_PROPERTY]);\n    edit->border_color      = nk_rgba(0,0,0,0);\n    edit->cursor_normal     = table[NK_COLOR_TEXT];\n    edit->cursor_hover      = table[NK_COLOR_TEXT];\n    edit->cursor_text_normal= table[NK_COLOR_EDIT];\n    edit->cursor_text_hover = table[NK_COLOR_EDIT];\n    edit->text_normal       = table[NK_COLOR_TEXT];\n    edit->text_hover        = table[NK_COLOR_TEXT];\n    edit->text_active       = table[NK_COLOR_TEXT];\n    edit->selected_normal   = table[NK_COLOR_TEXT];\n    edit->selected_hover    = table[NK_COLOR_TEXT];\n    edit->selected_text_normal  = table[NK_COLOR_EDIT];\n    edit->selected_text_hover   = table[NK_COLOR_EDIT];\n    edit->padding           = nk_vec2(0,0);\n    edit->cursor_size       = 8;\n    edit->border            = 0;\n    edit->rounding          = 0;\n    edit->color_factor      = 1.0f;\n    edit->disabled_factor   = NK_WIDGET_DISABLED_FACTOR;\n\n    /* chart */\n    chart = &style->chart;\n    nk_zero_struct(*chart);\n    chart->background       = nk_style_item_color(table[NK_COLOR_CHART]);\n    chart->border_color     = table[NK_COLOR_BORDER];\n    chart->selected_color   = table[NK_COLOR_CHART_COLOR_HIGHLIGHT];\n    chart->color            = table[NK_COLOR_CHART_COLOR];\n    chart->padding          = nk_vec2(4,4);\n    chart->border           = 0;\n    chart->rounding         = 0;\n    chart->color_factor     = 1.0f;\n    chart->disabled_factor  = NK_WIDGET_DISABLED_FACTOR;\n    chart->show_markers     = nk_true;\n\n    /* combo */\n    combo = &style->combo;\n    combo->normal           = nk_style_item_color(table[NK_COLOR_COMBO]);\n    combo->hover            = nk_style_item_color(table[NK_COLOR_COMBO]);\n    combo->active           = nk_style_item_color(table[NK_COLOR_COMBO]);\n    combo->border_color     = table[NK_COLOR_BORDER];\n    combo->label_normal     = table[NK_COLOR_TEXT];\n    combo->label_hover      = table[NK_COLOR_TEXT];\n    combo->label_active     = table[NK_COLOR_TEXT];\n    combo->sym_normal       = NK_SYMBOL_TRIANGLE_DOWN;\n    combo->sym_hover        = NK_SYMBOL_TRIANGLE_DOWN;\n    combo->sym_active       = NK_SYMBOL_TRIANGLE_DOWN;\n    combo->content_padding  = nk_vec2(4,4);\n    combo->button_padding   = nk_vec2(0,4);\n    combo->spacing          = nk_vec2(4,0);\n    combo->border           = 1;\n    combo->rounding         = 0;\n    combo->color_factor     = 1.0f;\n    combo->disabled_factor  = NK_WIDGET_DISABLED_FACTOR;\n\n    /* combo button */\n    button = &style->combo.button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_COMBO]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_COMBO]);\n    button->active          = nk_style_item_color(table[NK_COLOR_COMBO]);\n    button->border_color    = nk_rgba(0,0,0,0);\n    button->text_background = table[NK_COLOR_COMBO];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(2.0f,2.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n\n    /* tab */\n    tab = &style->tab;\n    tab->background         = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);\n    tab->border_color       = table[NK_COLOR_BORDER];\n    tab->text               = table[NK_COLOR_TEXT];\n    tab->sym_minimize       = NK_SYMBOL_TRIANGLE_RIGHT;\n    tab->sym_maximize       = NK_SYMBOL_TRIANGLE_DOWN;\n    tab->padding            = nk_vec2(4,4);\n    tab->spacing            = nk_vec2(4,4);\n    tab->indent             = 10.0f;\n    tab->border             = 1;\n    tab->rounding           = 0;\n    tab->color_factor       = 1.0f;\n    tab->disabled_factor    = NK_WIDGET_DISABLED_FACTOR;\n\n    /* tab button */\n    button = &style->tab.tab_minimize_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);\n    button->active          = nk_style_item_color(table[NK_COLOR_TAB_HEADER]);\n    button->border_color    = nk_rgba(0,0,0,0);\n    button->text_background = table[NK_COLOR_TAB_HEADER];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(2.0f,2.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n    style->tab.tab_maximize_button =*button;\n\n    /* node button */\n    button = &style->tab.node_minimize_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->active          = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    button->border_color    = nk_rgba(0,0,0,0);\n    button->text_background = table[NK_COLOR_TAB_HEADER];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(2.0f,2.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n    style->tab.node_maximize_button =*button;\n\n    /* window header */\n    win = &style->window;\n    win->header.align = NK_HEADER_RIGHT;\n    win->header.close_symbol = NK_SYMBOL_X;\n    win->header.minimize_symbol = NK_SYMBOL_MINUS;\n    win->header.maximize_symbol = NK_SYMBOL_PLUS;\n    win->header.normal = nk_style_item_color(table[NK_COLOR_HEADER]);\n    win->header.hover = nk_style_item_color(table[NK_COLOR_HEADER]);\n    win->header.active = nk_style_item_color(table[NK_COLOR_HEADER]);\n    win->header.label_normal = table[NK_COLOR_TEXT];\n    win->header.label_hover = table[NK_COLOR_TEXT];\n    win->header.label_active = table[NK_COLOR_TEXT];\n    win->header.label_padding = nk_vec2(4,4);\n    win->header.padding = nk_vec2(4,4);\n    win->header.spacing = nk_vec2(0,0);\n\n    /* window header close button */\n    button = &style->window.header.close_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_HEADER]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_HEADER]);\n    button->active          = nk_style_item_color(table[NK_COLOR_HEADER]);\n    button->border_color    = nk_rgba(0,0,0,0);\n    button->text_background = table[NK_COLOR_HEADER];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(0.0f,0.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n\n    /* window header minimize button */\n    button = &style->window.header.minimize_button;\n    nk_zero_struct(*button);\n    button->normal          = nk_style_item_color(table[NK_COLOR_HEADER]);\n    button->hover           = nk_style_item_color(table[NK_COLOR_HEADER]);\n    button->active          = nk_style_item_color(table[NK_COLOR_HEADER]);\n    button->border_color    = nk_rgba(0,0,0,0);\n    button->text_background = table[NK_COLOR_HEADER];\n    button->text_normal     = table[NK_COLOR_TEXT];\n    button->text_hover      = table[NK_COLOR_TEXT];\n    button->text_active     = table[NK_COLOR_TEXT];\n    button->padding         = nk_vec2(0.0f,0.0f);\n    button->touch_padding   = nk_vec2(0.0f,0.0f);\n    button->userdata        = nk_handle_ptr(0);\n    button->text_alignment  = NK_TEXT_CENTERED;\n    button->border          = 0.0f;\n    button->rounding        = 0.0f;\n    button->color_factor_text    = 1.0f;\n    button->color_factor_background = 1.0f;\n    button->disabled_factor = NK_WIDGET_DISABLED_FACTOR;\n    button->draw_begin      = 0;\n    button->draw_end        = 0;\n\n    /* window */\n    win->background = table[NK_COLOR_WINDOW];\n    win->fixed_background = nk_style_item_color(table[NK_COLOR_WINDOW]);\n    win->border_color = table[NK_COLOR_BORDER];\n    win->popup_border_color = table[NK_COLOR_BORDER];\n    win->combo_border_color = table[NK_COLOR_BORDER];\n    win->contextual_border_color = table[NK_COLOR_BORDER];\n    win->menu_border_color = table[NK_COLOR_BORDER];\n    win->group_border_color = table[NK_COLOR_BORDER];\n    win->tooltip_border_color = table[NK_COLOR_BORDER];\n    win->scaler = nk_style_item_color(table[NK_COLOR_TEXT]);\n\n    win->rounding = 0.0f;\n    win->spacing = nk_vec2(4,4);\n    win->scrollbar_size = nk_vec2(10,10);\n    win->min_size = nk_vec2(64,64);\n\n    win->combo_border = 1.0f;\n    win->contextual_border = 1.0f;\n    win->menu_border = 1.0f;\n    win->group_border = 1.0f;\n    win->tooltip_border = 1.0f;\n    win->popup_border = 1.0f;\n    win->border = 2.0f;\n    win->min_row_height_padding = 8;\n\n    win->padding = nk_vec2(4,4);\n    win->group_padding = nk_vec2(4,4);\n    win->popup_padding = nk_vec2(4,4);\n    win->combo_padding = nk_vec2(4,4);\n    win->contextual_padding = nk_vec2(4,4);\n    win->menu_padding = nk_vec2(4,4);\n    win->tooltip_padding = nk_vec2(4,4);\n\n    /* default tooltip just down and to the right of the cursor\n     * so it doesn't cover the text\n     *\n     * TODO might be worth consolidating tooltip styling\n     * into its own style structure, though it is a\n     * type of window...*/\n    win->tooltip_origin = NK_TOP_LEFT;\n    win->tooltip_offset = nk_vec2(12, 12);\n}\nNK_API void\nnk_style_set_font(struct nk_context *ctx, const struct nk_user_font *font)\n{\n    struct nk_style *style;\n    NK_ASSERT(ctx);\n\n    if (!ctx) return;\n    style = &ctx->style;\n    style->font = font;\n    ctx->stacks.fonts.head = 0;\n    if (ctx->current)\n        nk_layout_reset_min_row_height(ctx);\n}\nNK_API nk_bool\nnk_style_push_font(struct nk_context *ctx, const struct nk_user_font *font)\n{\n    struct nk_config_stack_user_font *font_stack;\n    struct nk_config_stack_user_font_element *element;\n\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n\n    font_stack = &ctx->stacks.fonts;\n    NK_ASSERT(font_stack->head < (int)NK_LEN(font_stack->elements));\n    if (font_stack->head >= (int)NK_LEN(font_stack->elements))\n        return 0;\n\n    element = &font_stack->elements[font_stack->head++];\n    element->address = &ctx->style.font;\n    element->old_value = ctx->style.font;\n    ctx->style.font = font;\n    return 1;\n}\nNK_API nk_bool\nnk_style_pop_font(struct nk_context *ctx)\n{\n    struct nk_config_stack_user_font *font_stack;\n    struct nk_config_stack_user_font_element *element;\n\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n\n    font_stack = &ctx->stacks.fonts;\n    NK_ASSERT(font_stack->head > 0);\n    if (font_stack->head < 1)\n        return 0;\n\n    element = &font_stack->elements[--font_stack->head];\n    *element->address = element->old_value;\n    return 1;\n}\n#define NK_STYLE_PUSH_IMPLEMENATION(prefix, type, stack) \\\nnk_style_push_##type(struct nk_context *ctx, prefix##_##type *address, prefix##_##type value)\\\n{\\\n    struct nk_config_stack_##type * type_stack;\\\n    struct nk_config_stack_##type##_element *element;\\\n    NK_ASSERT(ctx);\\\n    if (!ctx) return 0;\\\n    type_stack = &ctx->stacks.stack;\\\n    NK_ASSERT(type_stack->head < (int)NK_LEN(type_stack->elements));\\\n    if (type_stack->head >= (int)NK_LEN(type_stack->elements))\\\n        return 0;\\\n    element = &type_stack->elements[type_stack->head++];\\\n    element->address = address;\\\n    element->old_value = *address;\\\n    *address = value;\\\n    return 1;\\\n}\n#define NK_STYLE_POP_IMPLEMENATION(type, stack) \\\nnk_style_pop_##type(struct nk_context *ctx)\\\n{\\\n    struct nk_config_stack_##type *type_stack;\\\n    struct nk_config_stack_##type##_element *element;\\\n    NK_ASSERT(ctx);\\\n    if (!ctx) return 0;\\\n    type_stack = &ctx->stacks.stack;\\\n    NK_ASSERT(type_stack->head > 0);\\\n    if (type_stack->head < 1)\\\n        return 0;\\\n    element = &type_stack->elements[--type_stack->head];\\\n    *element->address = element->old_value;\\\n    return 1;\\\n}\nNK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk, style_item, style_items)\nNK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(nk,float, floats)\nNK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk, vec2, vectors)\nNK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(nk,flags, flags)\nNK_API nk_bool NK_STYLE_PUSH_IMPLEMENATION(struct nk,color, colors)\n\nNK_API nk_bool NK_STYLE_POP_IMPLEMENATION(style_item, style_items)\nNK_API nk_bool NK_STYLE_POP_IMPLEMENATION(float,floats)\nNK_API nk_bool NK_STYLE_POP_IMPLEMENATION(vec2, vectors)\nNK_API nk_bool NK_STYLE_POP_IMPLEMENATION(flags,flags)\nNK_API nk_bool NK_STYLE_POP_IMPLEMENATION(color,colors)\n\nNK_API nk_bool\nnk_style_set_cursor(struct nk_context *ctx, enum nk_style_cursor c)\n{\n    struct nk_style *style;\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    style = &ctx->style;\n    if (style->cursors[c]) {\n        style->cursor_active = style->cursors[c];\n        return 1;\n    }\n    return 0;\n}\nNK_API void\nnk_style_show_cursor(struct nk_context *ctx)\n{\n    ctx->style.cursor_visible = nk_true;\n}\nNK_API void\nnk_style_hide_cursor(struct nk_context *ctx)\n{\n    ctx->style.cursor_visible = nk_false;\n}\nNK_API void\nnk_style_load_cursor(struct nk_context *ctx, enum nk_style_cursor cursor,\n    const struct nk_cursor *c)\n{\n    struct nk_style *style;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    style = &ctx->style;\n    style->cursors[cursor] = c;\n}\nNK_API void\nnk_style_load_all_cursors(struct nk_context *ctx, const struct nk_cursor *cursors)\n{\n    int i = 0;\n    struct nk_style *style;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    style = &ctx->style;\n    for (i = 0; i < NK_CURSOR_COUNT; ++i)\n        style->cursors[i] = &cursors[i];\n    style->cursor_visible = nk_true;\n}\n"
  },
  {
    "path": "src/nuklear_table.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              TABLE\n *\n * ===============================================================*/\nNK_LIB struct nk_table*\nnk_create_table(struct nk_context *ctx)\n{\n    struct nk_page_element *elem;\n    elem = nk_create_page_element(ctx);\n    if (!elem) return 0;\n    return &elem->data.tbl;\n}\nNK_LIB void\nnk_free_table(struct nk_context *ctx, struct nk_table *tbl)\n{\n    union nk_page_data *pd = NK_CONTAINER_OF(tbl, union nk_page_data, tbl);\n    struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);\n    nk_free_page_element(ctx, pe);\n}\nNK_LIB void\nnk_push_table(struct nk_window *win, struct nk_table *tbl)\n{\n    if (!win->tables) {\n        win->tables = tbl;\n        tbl->next = 0;\n        tbl->prev = 0;\n        tbl->size = 0;\n        win->table_count = 1;\n        return;\n    }\n    win->tables->prev = tbl;\n    tbl->next = win->tables;\n    tbl->prev = 0;\n    tbl->size = 0;\n    win->tables = tbl;\n    win->table_count++;\n}\nNK_LIB void\nnk_remove_table(struct nk_window *win, struct nk_table *tbl)\n{\n    if (win->tables == tbl)\n        win->tables = tbl->next;\n    if (tbl->next)\n        tbl->next->prev = tbl->prev;\n    if (tbl->prev)\n        tbl->prev->next = tbl->next;\n    tbl->next = 0;\n    tbl->prev = 0;\n}\nNK_LIB nk_uint*\nnk_add_value(struct nk_context *ctx, struct nk_window *win,\n            nk_hash name, nk_uint value)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(win);\n    if (!win || !ctx) return 0;\n    if (!win->tables || win->tables->size >= NK_VALUE_PAGE_CAPACITY) {\n        struct nk_table *tbl = nk_create_table(ctx);\n        NK_ASSERT(tbl);\n        if (!tbl) return 0;\n        nk_push_table(win, tbl);\n    }\n    win->tables->seq = win->seq;\n    win->tables->keys[win->tables->size] = name;\n    win->tables->values[win->tables->size] = value;\n    return &win->tables->values[win->tables->size++];\n}\nNK_LIB nk_uint*\nnk_find_value(const struct nk_window *win, nk_hash name)\n{\n    struct nk_table *iter = win->tables;\n    while (iter) {\n        unsigned int i = 0;\n        unsigned int size = iter->size;\n        for (i = 0; i < size; ++i) {\n            if (iter->keys[i] == name) {\n                iter->seq = win->seq;\n                return &iter->values[i];\n            }\n        } size = NK_VALUE_PAGE_CAPACITY;\n        iter = iter->next;\n    }\n    return 0;\n}\n"
  },
  {
    "path": "src/nuklear_text.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              TEXT\n *\n * ===============================================================*/\nNK_LIB void\nnk_widget_text(struct nk_command_buffer *o, struct nk_rect b,\n    const char *string, int len, const struct nk_text *t,\n    nk_flags a, const struct nk_user_font *f)\n{\n    struct nk_rect label;\n    float text_width;\n\n    NK_ASSERT(o);\n    NK_ASSERT(t);\n    if (!o || !t) return;\n\n    b.h = NK_MAX(b.h, 2 * t->padding.y);\n\n    text_width = f->width(f->userdata, f->height, (const char*)string, len);\n    text_width += (2.0f * t->padding.x);\n\n    /* use top-left alignment by default */\n    if (!(a & (NK_TEXT_ALIGN_LEFT | NK_TEXT_ALIGN_CENTERED | NK_TEXT_ALIGN_RIGHT)))\n        a |= NK_TEXT_ALIGN_LEFT;\n    if (!(a & (NK_TEXT_ALIGN_TOP | NK_TEXT_ALIGN_MIDDLE | NK_TEXT_ALIGN_BOTTOM)))\n        a |= NK_TEXT_ALIGN_TOP;\n\n    /* align in x-axis */\n    if (a & NK_TEXT_ALIGN_LEFT) {\n        label.x = b.x + t->padding.x;\n        label.w = NK_MAX(0, b.w - 2 * t->padding.x);\n    } else if (a & NK_TEXT_ALIGN_CENTERED) {\n        label.w = NK_MAX(1, 2 * t->padding.x + (float)text_width);\n        label.x = (b.x + t->padding.x + ((b.w - 2 * t->padding.x) - label.w) / 2);\n        label.x = NK_MAX(b.x + t->padding.x, label.x);\n        label.w = NK_MIN(b.x + b.w, label.x + label.w);\n        if (label.w >= label.x) label.w -= label.x;\n    } else if (a & NK_TEXT_ALIGN_RIGHT) {\n        label.x = NK_MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (float)text_width));\n        label.w = (float)text_width + 2 * t->padding.x;\n    }\n\n    /* align in y-axis */\n    if (a & NK_TEXT_ALIGN_TOP) {\n        label.y = b.y + t->padding.y;\n        label.h = NK_MIN(f->height, b.h - 2 * t->padding.y);\n    } else if (a & NK_TEXT_ALIGN_MIDDLE) {\n        label.y = b.y + b.h/2.0f - (float)f->height/2.0f;\n        label.h = NK_MAX(b.h/2.0f, b.h - (b.h/2.0f + f->height/2.0f));\n    } else if (a & NK_TEXT_ALIGN_BOTTOM) {\n        label.y = b.y + b.h - f->height;\n        label.h = f->height;\n    }\n\n    nk_draw_text(o, label, (const char*)string, len, f, t->background, t->text);\n}\nNK_LIB void\nnk_widget_text_wrap(struct nk_command_buffer *o, struct nk_rect b,\n    const char *string, int len, const struct nk_text *t,\n    const struct nk_user_font *f)\n{\n    float width;\n    int glyphs = 0;\n    int fitting = 0;\n    int done = 0;\n    struct nk_rect line;\n    struct nk_text text;\n    NK_INTERN nk_rune seperator[] = {' '};\n\n    NK_ASSERT(o);\n    NK_ASSERT(t);\n    if (!o || !t) return;\n\n    text.padding = nk_vec2(0,0);\n    text.background = t->background;\n    text.text = t->text;\n\n    b.w = NK_MAX(b.w, 2 * t->padding.x);\n    b.h = NK_MAX(b.h, 2 * t->padding.y);\n    b.h = b.h - 2 * t->padding.y;\n\n    line.x = b.x + t->padding.x;\n    line.y = b.y + t->padding.y;\n    line.w = b.w - 2 * t->padding.x;\n    line.h = 2 * t->padding.y + f->height;\n\n    fitting = nk_text_clamp(f, string, len, line.w, &glyphs, &width, seperator,NK_LEN(seperator));\n    while (done < len) {\n        if (!fitting || line.y + line.h >= (b.y + b.h)) break;\n        nk_widget_text(o, line, &string[done], fitting, &text, NK_TEXT_LEFT, f);\n        done += fitting;\n        line.y += f->height + 2 * t->padding.y;\n        fitting = nk_text_clamp(f, &string[done], len - done, line.w, &glyphs, &width, seperator,NK_LEN(seperator));\n    }\n}\nNK_API void\nnk_text_colored(struct nk_context *ctx, const char *str, int len,\n    nk_flags alignment, struct nk_color color)\n{\n    struct nk_window *win;\n    const struct nk_style *style;\n\n    struct nk_vec2 item_padding;\n    struct nk_rect bounds;\n    struct nk_text text;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) return;\n\n    win = ctx->current;\n    style = &ctx->style;\n    nk_panel_alloc_space(&bounds, ctx);\n    item_padding = style->text.padding;\n\n    text.padding.x = item_padding.x;\n    text.padding.y = item_padding.y;\n    text.background = style->window.background;\n    text.text = nk_rgb_factor(color, style->text.color_factor);\n    nk_widget_text(&win->buffer, bounds, str, len, &text, alignment, style->font);\n}\nNK_API void\nnk_text_wrap_colored(struct nk_context *ctx, const char *str,\n    int len, struct nk_color color)\n{\n    struct nk_window *win;\n    const struct nk_style *style;\n\n    struct nk_vec2 item_padding;\n    struct nk_rect bounds;\n    struct nk_text text;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout) return;\n\n    win = ctx->current;\n    style = &ctx->style;\n    nk_panel_alloc_space(&bounds, ctx);\n    item_padding = style->text.padding;\n\n    text.padding.x = item_padding.x;\n    text.padding.y = item_padding.y;\n    text.background = style->window.background;\n    text.text = nk_rgb_factor(color, style->text.color_factor);\n    nk_widget_text_wrap(&win->buffer, bounds, str, len, &text, style->font);\n}\n#ifdef NK_INCLUDE_STANDARD_VARARGS\nNK_API void\nnk_labelf_colored(struct nk_context *ctx, nk_flags flags,\n    struct nk_color color, const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    nk_labelfv_colored(ctx, flags, color, fmt, args);\n    va_end(args);\n}\nNK_API void\nnk_labelf_colored_wrap(struct nk_context *ctx, struct nk_color color,\n    const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    nk_labelfv_colored_wrap(ctx, color, fmt, args);\n    va_end(args);\n}\nNK_API void\nnk_labelf(struct nk_context *ctx, nk_flags flags, const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    nk_labelfv(ctx, flags, fmt, args);\n    va_end(args);\n}\nNK_API void\nnk_labelf_wrap(struct nk_context *ctx, const char *fmt,...)\n{\n    va_list args;\n    va_start(args, fmt);\n    nk_labelfv_wrap(ctx, fmt, args);\n    va_end(args);\n}\nNK_API void\nnk_labelfv_colored(struct nk_context *ctx, nk_flags flags,\n    struct nk_color color, const char *fmt, va_list args)\n{\n    char buf[256];\n    nk_strfmt(buf, NK_LEN(buf), fmt, args);\n    nk_label_colored(ctx, buf, flags, color);\n}\n\nNK_API void\nnk_labelfv_colored_wrap(struct nk_context *ctx, struct nk_color color,\n    const char *fmt, va_list args)\n{\n    char buf[256];\n    nk_strfmt(buf, NK_LEN(buf), fmt, args);\n    nk_label_colored_wrap(ctx, buf, color);\n}\n\nNK_API void\nnk_labelfv(struct nk_context *ctx, nk_flags flags, const char *fmt, va_list args)\n{\n    char buf[256];\n    nk_strfmt(buf, NK_LEN(buf), fmt, args);\n    nk_label(ctx, buf, flags);\n}\n\nNK_API void\nnk_labelfv_wrap(struct nk_context *ctx, const char *fmt, va_list args)\n{\n    char buf[256];\n    nk_strfmt(buf, NK_LEN(buf), fmt, args);\n    nk_label_wrap(ctx, buf);\n}\n\nNK_API void\nnk_value_bool(struct nk_context *ctx, const char *prefix, int value)\n{\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: %s\", prefix, ((value) ? \"true\": \"false\"));\n}\nNK_API void\nnk_value_int(struct nk_context *ctx, const char *prefix, int value)\n{\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: %d\", prefix, value);\n}\nNK_API void\nnk_value_uint(struct nk_context *ctx, const char *prefix, unsigned int value)\n{\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: %u\", prefix, value);\n}\nNK_API void\nnk_value_float(struct nk_context *ctx, const char *prefix, float value)\n{\n    double double_value = (double)value;\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: %.3f\", prefix, double_value);\n}\nNK_API void\nnk_value_color_byte(struct nk_context *ctx, const char *p, struct nk_color c)\n{\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: (%d, %d, %d, %d)\", p, c.r, c.g, c.b, c.a);\n}\nNK_API void\nnk_value_color_float(struct nk_context *ctx, const char *p, struct nk_color color)\n{\n    double c[4]; nk_color_dv(c, color);\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: (%.2f, %.2f, %.2f, %.2f)\",\n        p, c[0], c[1], c[2], c[3]);\n}\nNK_API void\nnk_value_color_hex(struct nk_context *ctx, const char *prefix, struct nk_color color)\n{\n    char hex[16];\n    nk_color_hex_rgba(hex, color);\n    nk_labelf(ctx, NK_TEXT_LEFT, \"%s: %s\", prefix, hex);\n}\n#endif\nNK_API void\nnk_text(struct nk_context *ctx, const char *str, int len, nk_flags alignment)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    nk_text_colored(ctx, str, len, alignment, ctx->style.text.color);\n}\nNK_API void\nnk_text_wrap(struct nk_context *ctx, const char *str, int len)\n{\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    nk_text_wrap_colored(ctx, str, len, ctx->style.text.color);\n}\nNK_API void\nnk_label(struct nk_context *ctx, const char *str, nk_flags alignment)\n{\n    nk_text(ctx, str, nk_strlen(str), alignment);\n}\nNK_API void\nnk_label_colored(struct nk_context *ctx, const char *str, nk_flags align,\n    struct nk_color color)\n{\n    nk_text_colored(ctx, str, nk_strlen(str), align, color);\n}\nNK_API void\nnk_label_wrap(struct nk_context *ctx, const char *str)\n{\n    nk_text_wrap(ctx, str, nk_strlen(str));\n}\nNK_API void\nnk_label_colored_wrap(struct nk_context *ctx, const char *str, struct nk_color color)\n{\n    nk_text_wrap_colored(ctx, str, nk_strlen(str), color);\n}\n\n"
  },
  {
    "path": "src/nuklear_text_editor.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                          TEXT EDITOR\n *\n * ===============================================================*/\n/* stb_textedit.h - v1.8  - public domain - Sean Barrett */\nstruct nk_text_find {\n   float x,y;    /* position of n'th character */\n   float height; /* height of line */\n   int first_char, length; /* first char of row, and length */\n   int prev_first;  /*_ first char of previous row */\n};\n\nstruct nk_text_edit_row {\n   float x0,x1;\n   /* starting x location, end x location (allows for align=right, etc) */\n   float baseline_y_delta;\n   /* position of baseline relative to previous row's baseline*/\n   float ymin,ymax;\n   /* height of row above and below baseline */\n   int num_chars;\n};\n\n/* forward declarations */\nNK_INTERN void nk_textedit_makeundo_delete(struct nk_text_edit*, int, int);\nNK_INTERN void nk_textedit_makeundo_insert(struct nk_text_edit*, int, int);\nNK_INTERN void nk_textedit_makeundo_replace(struct nk_text_edit*, int, int, int);\n#define NK_TEXT_HAS_SELECTION(s)   ((s)->select_start != (s)->select_end)\n\nNK_INTERN float\nnk_textedit_get_width(const struct nk_text_edit *edit, int line_start, int char_id,\n    const struct nk_user_font *font)\n{\n    int len = 0;\n    nk_rune unicode = 0;\n    const char *str = nk_str_at_const(&edit->string, line_start + char_id, &unicode, &len);\n    return font->width(font->userdata, font->height, str, len);\n}\nNK_INTERN void\nnk_textedit_layout_row(struct nk_text_edit_row *r, struct nk_text_edit *edit,\n    int line_start_id, float row_height, const struct nk_user_font *font)\n{\n    int l;\n    int glyphs = 0;\n    nk_rune unicode;\n    const char *remaining;\n    int len = nk_str_len_char(&edit->string);\n    const char *end = nk_str_get_const(&edit->string) + len;\n    const char *text = nk_str_at_const(&edit->string, line_start_id, &unicode, &l);\n    const struct nk_vec2 size = nk_text_calculate_text_bounds(font,\n        text, (int)(end - text), row_height, &remaining, 0, &glyphs, NK_STOP_ON_NEW_LINE);\n\n    r->x0 = 0.0f;\n    r->x1 = size.x;\n    r->baseline_y_delta = size.y;\n    r->ymin = 0.0f;\n    r->ymax = size.y;\n    r->num_chars = glyphs;\n}\nNK_INTERN int\nnk_textedit_locate_coord(struct nk_text_edit *edit, float x, float y,\n    const struct nk_user_font *font, float row_height)\n{\n    struct nk_text_edit_row r;\n    int n = edit->string.len;\n    float base_y = 0, prev_x;\n    int i=0, k;\n\n    r.x0 = r.x1 = 0;\n    r.ymin = r.ymax = 0;\n    r.num_chars = 0;\n\n    /* search rows to find one that straddles 'y' */\n    while (i < n) {\n        nk_textedit_layout_row(&r, edit, i, row_height, font);\n        if (r.num_chars <= 0)\n            return n;\n\n        if (i==0 && y < base_y + r.ymin)\n            return 0;\n\n        if (y < base_y + r.ymax)\n            break;\n\n        i += r.num_chars;\n        base_y += r.baseline_y_delta;\n    }\n\n    /* below all text, return 'after' last character */\n    if (i >= n)\n        return n;\n\n    /* check if it's before the beginning of the line */\n    if (x < r.x0)\n        return i;\n\n    /* check if it's before the end of the line */\n    if (x < r.x1) {\n        /* search characters in row for one that straddles 'x' */\n        k = i;\n        prev_x = r.x0;\n        for (i=0; i < r.num_chars; ++i) {\n            float w = nk_textedit_get_width(edit, k, i, font);\n            if (x < prev_x+w) {\n                if (x < prev_x+w/2)\n                    return k+i;\n                else return k+i+1;\n            }\n            prev_x += w;\n        }\n        /* shouldn't happen, but if it does, fall through to end-of-line case */\n    }\n\n    /* if the last character is a newline, return that.\n     * otherwise return 'after' the last character */\n    if (nk_str_rune_at(&edit->string, i+r.num_chars-1) == '\\n')\n        return i+r.num_chars-1;\n    else return i+r.num_chars;\n}\nNK_LIB void\nnk_textedit_click(struct nk_text_edit *state, float x, float y,\n    const struct nk_user_font *font, float row_height)\n{\n    /* API click: on mouse down, move the cursor to the clicked location,\n     * and reset the selection */\n    state->cursor = nk_textedit_locate_coord(state, x, y, font, row_height);\n    state->select_start = state->cursor;\n    state->select_end = state->cursor;\n    state->has_preferred_x = 0;\n}\nNK_LIB void\nnk_textedit_drag(struct nk_text_edit *state, float x, float y,\n    const struct nk_user_font *font, float row_height)\n{\n    /* API drag: on mouse drag, move the cursor and selection endpoint\n     * to the clicked location */\n    int p = nk_textedit_locate_coord(state, x, y, font, row_height);\n    if (state->select_start == state->select_end)\n        state->select_start = state->cursor;\n    state->cursor = state->select_end = p;\n}\nNK_INTERN void\nnk_textedit_find_charpos(struct nk_text_find *find, struct nk_text_edit *state,\n    int n, int single_line, const struct nk_user_font *font, float row_height)\n{\n    /* find the x/y location of a character, and remember info about the previous\n     * row in case we get a move-up event (for page up, we'll have to rescan) */\n    struct nk_text_edit_row r;\n    int prev_start = 0;\n    int z = state->string.len;\n    int i=0, first;\n\n    nk_zero_struct(r);\n    if (n == z) {\n        /* if it's at the end, then find the last line -- simpler than trying to\n        explicitly handle this case in the regular code */\n        nk_textedit_layout_row(&r, state, 0, row_height, font);\n        if (single_line) {\n            find->first_char = 0;\n            find->length = z;\n        } else {\n            while (i < z) {\n                prev_start = i;\n                i += r.num_chars;\n                nk_textedit_layout_row(&r, state, i, row_height, font);\n            }\n\n            find->first_char = i;\n            find->length = r.num_chars;\n        }\n        find->x = r.x1;\n        find->y = r.ymin;\n        find->height = r.ymax - r.ymin;\n        find->prev_first = prev_start;\n        return;\n    }\n\n    /* search rows to find the one that straddles character n */\n    find->y = 0;\n\n    for(;;) {\n        nk_textedit_layout_row(&r, state, i, row_height, font);\n        if (n < i + r.num_chars) break;\n        prev_start = i;\n        i += r.num_chars;\n        find->y += r.baseline_y_delta;\n    }\n\n    find->first_char = first = i;\n    find->length = r.num_chars;\n    find->height = r.ymax - r.ymin;\n    find->prev_first = prev_start;\n\n    /* now scan to find xpos */\n    find->x = r.x0;\n    for (i=0; first+i < n; ++i)\n        find->x += nk_textedit_get_width(state, first, i, font);\n}\nNK_INTERN void\nnk_textedit_clamp(struct nk_text_edit *state)\n{\n    /* make the selection/cursor state valid if client altered the string */\n    int n = state->string.len;\n    if (NK_TEXT_HAS_SELECTION(state)) {\n        if (state->select_start > n) state->select_start = n;\n        if (state->select_end   > n) state->select_end = n;\n        /* if clamping forced them to be equal, move the cursor to match */\n        if (state->select_start == state->select_end)\n            state->cursor = state->select_start;\n    }\n    if (state->cursor > n) state->cursor = n;\n}\nNK_API void\nnk_textedit_delete(struct nk_text_edit *state, int where, int len)\n{\n    /* delete characters while updating undo */\n    nk_textedit_makeundo_delete(state, where, len);\n    nk_str_delete_runes(&state->string, where, len);\n    state->has_preferred_x = 0;\n}\nNK_API void\nnk_textedit_delete_selection(struct nk_text_edit *state)\n{\n    /* delete the section */\n    nk_textedit_clamp(state);\n    if (NK_TEXT_HAS_SELECTION(state)) {\n        if (state->select_start < state->select_end) {\n            nk_textedit_delete(state, state->select_start,\n                state->select_end - state->select_start);\n            state->select_end = state->cursor = state->select_start;\n        } else {\n            nk_textedit_delete(state, state->select_end,\n                state->select_start - state->select_end);\n            state->select_start = state->cursor = state->select_end;\n        }\n        state->has_preferred_x = 0;\n    }\n}\nNK_INTERN void\nnk_textedit_sortselection(struct nk_text_edit *state)\n{\n    /* canonicalize the selection so start <= end */\n    if (state->select_end < state->select_start) {\n        int temp = state->select_end;\n        state->select_end = state->select_start;\n        state->select_start = temp;\n    }\n}\nNK_INTERN void\nnk_textedit_move_to_first(struct nk_text_edit *state)\n{\n    /* move cursor to first character of selection */\n    if (NK_TEXT_HAS_SELECTION(state)) {\n        nk_textedit_sortselection(state);\n        state->cursor = state->select_start;\n        state->select_end = state->select_start;\n        state->has_preferred_x = 0;\n    }\n}\nNK_INTERN void\nnk_textedit_move_to_last(struct nk_text_edit *state)\n{\n    /* move cursor to last character of selection */\n    if (NK_TEXT_HAS_SELECTION(state)) {\n        nk_textedit_sortselection(state);\n        nk_textedit_clamp(state);\n        state->cursor = state->select_end;\n        state->select_start = state->select_end;\n        state->has_preferred_x = 0;\n    }\n}\nNK_INTERN int\nnk_is_word_boundary( struct nk_text_edit *state, int idx)\n{\n    int len;\n    nk_rune c;\n    if (idx < 0) return 1;\n    if (!nk_str_at_rune(&state->string, idx, &c, &len)) return 1;\n#ifndef NK_IS_WORD_BOUNDARY\n    return (c == ' ' || c == '\\t' || c == '\\n' || c == '\\r' || c == '\\f' ||\n            c == '\\v' || c == 0x3000);\n#else\n    return NK_IS_WORD_BOUNDARY(c);\n#endif\n}\nNK_INTERN int\nnk_textedit_move_to_word_previous(struct nk_text_edit *state)\n{\n   int c = state->cursor - 1;\n   if (c > 0) {\n      if (nk_is_word_boundary(state, c)) {\n         while (c > 0 && nk_is_word_boundary(state, --c));\n      }\n      while (!nk_is_word_boundary(state, --c));\n      c++;\n   } else {\n      return 0;\n   }\n\n   return c;\n}\nNK_INTERN int\nnk_textedit_move_to_word_next(struct nk_text_edit *state)\n{\n   const int len = state->string.len;\n   int c = state->cursor;\n   if (c < len) {\n      if (!nk_is_word_boundary(state, c)) {\n         while (c < len && !nk_is_word_boundary(state, ++c));\n      }\n      while (c < len && nk_is_word_boundary(state, ++c));\n   } else {\n      return len;\n   }\n\n   return c;\n}\nNK_INTERN void\nnk_textedit_prep_selection_at_cursor(struct nk_text_edit *state)\n{\n    /* update selection and cursor to match each other */\n    if (!NK_TEXT_HAS_SELECTION(state))\n        state->select_start = state->select_end = state->cursor;\n    else state->cursor = state->select_end;\n}\nNK_API nk_bool\nnk_textedit_cut(struct nk_text_edit *state)\n{\n    /* API cut: delete selection */\n    if (state->mode == NK_TEXT_EDIT_MODE_VIEW)\n        return 0;\n    if (NK_TEXT_HAS_SELECTION(state)) {\n        nk_textedit_delete_selection(state); /* implicitly clamps */\n        state->has_preferred_x = 0;\n        return 1;\n    }\n   return 0;\n}\nNK_API nk_bool\nnk_textedit_paste(struct nk_text_edit *state, char const *ctext, int len)\n{\n    /* API paste: replace existing selection with passed-in text */\n    int glyphs;\n    const char *text = (const char *) ctext;\n    if (state->mode == NK_TEXT_EDIT_MODE_VIEW) return 0;\n\n    /* if there's a selection, the paste should delete it */\n    nk_textedit_clamp(state);\n    nk_textedit_delete_selection(state);\n\n    /* try to insert the characters */\n    glyphs = nk_utf_len(ctext, len);\n    if (nk_str_insert_text_char(&state->string, state->cursor, text, len)) {\n        nk_textedit_makeundo_insert(state, state->cursor, glyphs);\n        state->cursor += len;\n        state->has_preferred_x = 0;\n        return 1;\n    }\n    /* remove the undo since we didn't actually insert the characters */\n    if (state->undo.undo_point)\n        --state->undo.undo_point;\n    return 0;\n}\nNK_API void\nnk_textedit_text(struct nk_text_edit *state, const char *text, int total_len)\n{\n    nk_rune unicode;\n    int glyph_len;\n    int text_len = 0;\n\n    NK_ASSERT(state);\n    NK_ASSERT(text);\n    if (!text || !total_len || state->mode == NK_TEXT_EDIT_MODE_VIEW) return;\n\n    glyph_len = nk_utf_decode(text, &unicode, total_len);\n    while ((text_len < total_len) && glyph_len)\n    {\n        /* don't insert a backward delete, just process the event */\n        if (unicode == 127) goto next;\n        /* can't add newline in single-line mode */\n        if (unicode == '\\n' && state->single_line) goto next;\n        /* filter incoming text */\n        if (state->filter && !state->filter(state, unicode)) goto next;\n\n        if (!NK_TEXT_HAS_SELECTION(state) &&\n            state->cursor < state->string.len)\n        {\n            if (state->mode == NK_TEXT_EDIT_MODE_REPLACE) {\n                nk_textedit_makeundo_replace(state, state->cursor, 1, 1);\n                nk_str_delete_runes(&state->string, state->cursor, 1);\n            }\n            if (nk_str_insert_text_utf8(&state->string, state->cursor,\n                                        text+text_len, 1))\n            {\n                ++state->cursor;\n                state->has_preferred_x = 0;\n            }\n        } else {\n            nk_textedit_delete_selection(state); /* implicitly clamps */\n            if (nk_str_insert_text_utf8(&state->string, state->cursor,\n                                        text+text_len, 1))\n            {\n                nk_textedit_makeundo_insert(state, state->cursor, 1);\n                state->cursor = NK_MIN(state->cursor + 1, state->string.len);\n                state->has_preferred_x = 0;\n            }\n        }\n        next:\n        text_len += glyph_len;\n        glyph_len = nk_utf_decode(text + text_len, &unicode, total_len-text_len);\n    }\n}\nNK_LIB void\nnk_textedit_key(struct nk_text_edit *state, enum nk_keys key, int shift_mod,\n    const struct nk_user_font *font, float row_height)\n{\nretry:\n    switch (key)\n    {\n    case NK_KEY_NONE:\n    case NK_KEY_CTRL:\n    case NK_KEY_ENTER:\n    case NK_KEY_SHIFT:\n    case NK_KEY_TAB:\n    case NK_KEY_COPY:\n    case NK_KEY_CUT:\n    case NK_KEY_PASTE:\n    case NK_KEY_MAX:\n    default: break;\n    case NK_KEY_TEXT_UNDO:\n         nk_textedit_undo(state);\n         state->has_preferred_x = 0;\n         break;\n\n    case NK_KEY_TEXT_REDO:\n        nk_textedit_redo(state);\n        state->has_preferred_x = 0;\n        break;\n\n    case NK_KEY_TEXT_SELECT_ALL:\n        nk_textedit_select_all(state);\n        state->has_preferred_x = 0;\n        break;\n\n    case NK_KEY_TEXT_INSERT_MODE:\n        state->mode = NK_TEXT_EDIT_MODE_INSERT;\n        break;\n    case NK_KEY_TEXT_REPLACE_MODE:\n        state->mode = NK_TEXT_EDIT_MODE_REPLACE;\n        break;\n    case NK_KEY_TEXT_RESET_MODE:\n        state->mode = NK_TEXT_EDIT_MODE_VIEW;\n        break;\n\n    case NK_KEY_LEFT:\n        if (shift_mod) {\n            nk_textedit_clamp(state);\n            nk_textedit_prep_selection_at_cursor(state);\n            /* move selection left */\n            if (state->select_end > 0)\n                --state->select_end;\n            state->cursor = state->select_end;\n            state->has_preferred_x = 0;\n        } else {\n            /* if currently there's a selection,\n             * move cursor to start of selection */\n            if (NK_TEXT_HAS_SELECTION(state))\n                nk_textedit_move_to_first(state);\n            else if (state->cursor > 0)\n               --state->cursor;\n            state->has_preferred_x = 0;\n        } break;\n\n    case NK_KEY_RIGHT:\n        if (shift_mod) {\n            nk_textedit_prep_selection_at_cursor(state);\n            /* move selection right */\n            ++state->select_end;\n            nk_textedit_clamp(state);\n            state->cursor = state->select_end;\n            state->has_preferred_x = 0;\n        } else {\n            /* if currently there's a selection,\n             * move cursor to end of selection */\n            if (NK_TEXT_HAS_SELECTION(state))\n                nk_textedit_move_to_last(state);\n            else ++state->cursor;\n            nk_textedit_clamp(state);\n            state->has_preferred_x = 0;\n        } break;\n\n    case NK_KEY_TEXT_WORD_LEFT:\n        if (shift_mod) {\n            if( !NK_TEXT_HAS_SELECTION( state ) )\n                nk_textedit_prep_selection_at_cursor(state);\n            state->cursor = nk_textedit_move_to_word_previous(state);\n            state->select_end = state->cursor;\n            nk_textedit_clamp(state );\n        } else {\n            if (NK_TEXT_HAS_SELECTION(state))\n                nk_textedit_move_to_first(state);\n            else {\n                state->cursor = nk_textedit_move_to_word_previous(state);\n                nk_textedit_clamp(state );\n            }\n        } break;\n\n    case NK_KEY_TEXT_WORD_RIGHT:\n        if (shift_mod) {\n            if( !NK_TEXT_HAS_SELECTION( state ) )\n                nk_textedit_prep_selection_at_cursor(state);\n            state->cursor = nk_textedit_move_to_word_next(state);\n            state->select_end = state->cursor;\n            nk_textedit_clamp(state);\n        } else {\n            if (NK_TEXT_HAS_SELECTION(state))\n                nk_textedit_move_to_last(state);\n            else {\n                state->cursor = nk_textedit_move_to_word_next(state);\n                nk_textedit_clamp(state );\n            }\n        } break;\n\n    case NK_KEY_DOWN: {\n        struct nk_text_find find;\n        struct nk_text_edit_row row;\n        int i, sel = shift_mod;\n\n        if (state->single_line) {\n            /* on windows, up&down in single-line behave like left&right */\n            key = NK_KEY_RIGHT;\n            goto retry;\n        }\n\n        if (sel)\n            nk_textedit_prep_selection_at_cursor(state);\n        else if (NK_TEXT_HAS_SELECTION(state))\n            nk_textedit_move_to_last(state);\n\n        /* compute current position of cursor point */\n        nk_textedit_clamp(state);\n        nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,\n            font, row_height);\n\n        /* now find character position down a row */\n        if (find.length)\n        {\n            float x;\n            float goal_x = state->has_preferred_x ? state->preferred_x : find.x;\n            int start = find.first_char + find.length;\n\n            state->cursor = start;\n            nk_textedit_layout_row(&row, state, state->cursor, row_height, font);\n            x = row.x0;\n\n            for (i=0; i < row.num_chars && x < row.x1; ++i) {\n                float dx = nk_textedit_get_width(state, start, i, font);\n                x += dx;\n                if (x > goal_x)\n                    break;\n                ++state->cursor;\n            }\n            nk_textedit_clamp(state);\n\n            state->has_preferred_x = 1;\n            state->preferred_x = goal_x;\n            if (sel)\n                state->select_end = state->cursor;\n        }\n    } break;\n\n    case NK_KEY_UP: {\n        struct nk_text_find find;\n        struct nk_text_edit_row row;\n        int i, sel = shift_mod;\n\n        if (state->single_line) {\n            /* on windows, up&down become left&right */\n            key = NK_KEY_LEFT;\n            goto retry;\n        }\n\n        if (sel)\n            nk_textedit_prep_selection_at_cursor(state);\n        else if (NK_TEXT_HAS_SELECTION(state))\n            nk_textedit_move_to_first(state);\n\n         /* compute current position of cursor point */\n         nk_textedit_clamp(state);\n         nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,\n                font, row_height);\n\n         /* can only go up if there's a previous row */\n         if (find.prev_first != find.first_char) {\n            /* now find character position up a row */\n            float x;\n            float goal_x = state->has_preferred_x ? state->preferred_x : find.x;\n\n            state->cursor = find.prev_first;\n            nk_textedit_layout_row(&row, state, state->cursor, row_height, font);\n            x = row.x0;\n\n            for (i=0; i < row.num_chars && x < row.x1; ++i) {\n                float dx = nk_textedit_get_width(state, find.prev_first, i, font);\n                x += dx;\n                if (x > goal_x)\n                    break;\n                ++state->cursor;\n            }\n            nk_textedit_clamp(state);\n\n            state->has_preferred_x = 1;\n            state->preferred_x = goal_x;\n            if (sel) state->select_end = state->cursor;\n         }\n      } break;\n\n    case NK_KEY_DEL:\n        if (state->mode == NK_TEXT_EDIT_MODE_VIEW)\n            break;\n        if (NK_TEXT_HAS_SELECTION(state))\n            nk_textedit_delete_selection(state);\n        else {\n            int n = state->string.len;\n            if (state->cursor < n)\n                nk_textedit_delete(state, state->cursor, 1);\n         }\n         state->has_preferred_x = 0;\n         break;\n\n    case NK_KEY_BACKSPACE:\n        if (state->mode == NK_TEXT_EDIT_MODE_VIEW)\n            break;\n        if (NK_TEXT_HAS_SELECTION(state))\n            nk_textedit_delete_selection(state);\n        else {\n            nk_textedit_clamp(state);\n            if (state->cursor > 0) {\n                nk_textedit_delete(state, state->cursor-1, 1);\n                --state->cursor;\n            }\n         }\n         state->has_preferred_x = 0;\n         break;\n\n    case NK_KEY_TEXT_START:\n         if (shift_mod) {\n            nk_textedit_prep_selection_at_cursor(state);\n            state->cursor = state->select_end = 0;\n            state->has_preferred_x = 0;\n         } else {\n            state->cursor = state->select_start = state->select_end = 0;\n            state->has_preferred_x = 0;\n         }\n         break;\n\n    case NK_KEY_TEXT_END:\n         if (shift_mod) {\n            nk_textedit_prep_selection_at_cursor(state);\n            state->cursor = state->select_end = state->string.len;\n            state->has_preferred_x = 0;\n         } else {\n            state->cursor = state->string.len;\n            state->select_start = state->select_end = 0;\n            state->has_preferred_x = 0;\n         }\n         break;\n\n    case NK_KEY_TEXT_LINE_START: {\n        if (shift_mod) {\n            struct nk_text_find find;\n           nk_textedit_clamp(state);\n            nk_textedit_prep_selection_at_cursor(state);\n            if (state->string.len && state->cursor == state->string.len)\n                --state->cursor;\n            nk_textedit_find_charpos(&find, state,state->cursor, state->single_line,\n                font, row_height);\n            state->cursor = state->select_end = find.first_char;\n            state->has_preferred_x = 0;\n        } else {\n            struct nk_text_find find;\n            if (state->string.len && state->cursor == state->string.len)\n                --state->cursor;\n            nk_textedit_clamp(state);\n            nk_textedit_move_to_first(state);\n            nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,\n                font, row_height);\n            state->cursor = find.first_char;\n            state->has_preferred_x = 0;\n        }\n      } break;\n\n    case NK_KEY_TEXT_LINE_END: {\n        if (shift_mod) {\n            struct nk_text_find find;\n            nk_textedit_clamp(state);\n            nk_textedit_prep_selection_at_cursor(state);\n            nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,\n                font, row_height);\n            state->has_preferred_x = 0;\n            state->cursor = find.first_char + find.length;\n            if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\\n')\n                --state->cursor;\n            state->select_end = state->cursor;\n        } else {\n            struct nk_text_find find;\n            nk_textedit_clamp(state);\n            nk_textedit_move_to_first(state);\n            nk_textedit_find_charpos(&find, state, state->cursor, state->single_line,\n                font, row_height);\n\n            state->has_preferred_x = 0;\n            state->cursor = find.first_char + find.length;\n            if (find.length > 0 && nk_str_rune_at(&state->string, state->cursor-1) == '\\n')\n                --state->cursor;\n        }} break;\n    }\n}\nNK_INTERN void\nnk_textedit_flush_redo(struct nk_text_undo_state *state)\n{\n    state->redo_point = NK_TEXTEDIT_UNDOSTATECOUNT;\n    state->redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT;\n}\nNK_INTERN void\nnk_textedit_discard_undo(struct nk_text_undo_state *state)\n{\n    /* discard the oldest entry in the undo list */\n    if (state->undo_point > 0) {\n        /* if the 0th undo state has characters, clean those up */\n        if (state->undo_rec[0].char_storage >= 0) {\n            int n = state->undo_rec[0].insert_length, i;\n            /* delete n characters from all other records */\n            state->undo_char_point = (short)(state->undo_char_point - n);\n            NK_MEMCPY(state->undo_char, state->undo_char + n,\n                (nk_size)state->undo_char_point*sizeof(nk_rune));\n            for (i=0; i < state->undo_point; ++i) {\n                if (state->undo_rec[i].char_storage >= 0)\n                state->undo_rec[i].char_storage = (short)\n                    (state->undo_rec[i].char_storage - n);\n            }\n        }\n        --state->undo_point;\n        NK_MEMCPY(state->undo_rec, state->undo_rec+1,\n            (nk_size)((nk_size)state->undo_point * sizeof(state->undo_rec[0])));\n    }\n}\nNK_INTERN void\nnk_textedit_discard_redo(struct nk_text_undo_state *state)\n{\n/*  discard the oldest entry in the redo list--it's bad if this\n    ever happens, but because undo & redo have to store the actual\n    characters in different cases, the redo character buffer can\n    fill up even though the undo buffer didn't */\n    nk_size num;\n    int k = NK_TEXTEDIT_UNDOSTATECOUNT-1;\n    if (state->redo_point <= k) {\n        /* if the k'th undo state has characters, clean those up */\n        if (state->undo_rec[k].char_storage >= 0) {\n            int n = state->undo_rec[k].insert_length, i;\n            /* delete n characters from all other records */\n            state->redo_char_point = (short)(state->redo_char_point + n);\n            num = (nk_size)(NK_TEXTEDIT_UNDOCHARCOUNT - state->redo_char_point);\n            NK_MEMCPY(state->undo_char + state->redo_char_point,\n                state->undo_char + state->redo_char_point-n, num * sizeof(char));\n            for (i = state->redo_point; i < k; ++i) {\n                if (state->undo_rec[i].char_storage >= 0) {\n                    state->undo_rec[i].char_storage = (short)\n                        (state->undo_rec[i].char_storage + n);\n                }\n            }\n        }\n        ++state->redo_point;\n        num = (nk_size)(NK_TEXTEDIT_UNDOSTATECOUNT - state->redo_point);\n        if (num) NK_MEMCPY(state->undo_rec + state->redo_point-1,\n            state->undo_rec + state->redo_point, num * sizeof(state->undo_rec[0]));\n    }\n}\nNK_INTERN struct nk_text_undo_record*\nnk_textedit_create_undo_record(struct nk_text_undo_state *state, int numchars)\n{\n    /* any time we create a new undo record, we discard redo*/\n    nk_textedit_flush_redo(state);\n\n    /* if we have no free records, we have to make room,\n     * by sliding the existing records down */\n    if (state->undo_point == NK_TEXTEDIT_UNDOSTATECOUNT)\n        nk_textedit_discard_undo(state);\n\n    /* if the characters to store won't possibly fit in the buffer,\n     * we can't undo */\n    if (numchars > NK_TEXTEDIT_UNDOCHARCOUNT) {\n        state->undo_point = 0;\n        state->undo_char_point = 0;\n        return 0;\n    }\n\n    /* if we don't have enough free characters in the buffer,\n     * we have to make room */\n    while (state->undo_char_point + numchars > NK_TEXTEDIT_UNDOCHARCOUNT)\n        nk_textedit_discard_undo(state);\n    return &state->undo_rec[state->undo_point++];\n}\nNK_INTERN nk_rune*\nnk_textedit_createundo(struct nk_text_undo_state *state, int pos,\n    int insert_len, int delete_len)\n{\n    struct nk_text_undo_record *r = nk_textedit_create_undo_record(state, insert_len);\n    if (r == 0)\n        return 0;\n\n    r->where = pos;\n    r->insert_length = (short) insert_len;\n    r->delete_length = (short) delete_len;\n\n    if (insert_len == 0) {\n        r->char_storage = -1;\n        return 0;\n    } else {\n        r->char_storage = state->undo_char_point;\n        state->undo_char_point = (short)(state->undo_char_point +  insert_len);\n        return &state->undo_char[r->char_storage];\n    }\n}\nNK_API void\nnk_textedit_undo(struct nk_text_edit *state)\n{\n    struct nk_text_undo_state *s = &state->undo;\n    struct nk_text_undo_record u, *r;\n    if (s->undo_point == 0)\n        return;\n\n    /* we need to do two things: apply the undo record, and create a redo record */\n    u = s->undo_rec[s->undo_point-1];\n    r = &s->undo_rec[s->redo_point-1];\n    r->char_storage = -1;\n\n    r->insert_length = u.delete_length;\n    r->delete_length = u.insert_length;\n    r->where = u.where;\n\n    if (u.delete_length)\n    {\n       /*   if the undo record says to delete characters, then the redo record will\n            need to re-insert the characters that get deleted, so we need to store\n            them.\n            there are three cases:\n                - there's enough room to store the characters\n                - characters stored for *redoing* don't leave room for redo\n                - characters stored for *undoing* don't leave room for redo\n            if the last is true, we have to bail */\n        if (s->undo_char_point + u.delete_length >= NK_TEXTEDIT_UNDOCHARCOUNT) {\n            /* the undo records take up too much character space; there's no space\n            * to store the redo characters */\n            r->insert_length = 0;\n        } else {\n            int i;\n            /* there's definitely room to store the characters eventually */\n            while (s->undo_char_point + u.delete_length > s->redo_char_point) {\n                /* there's currently not enough room, so discard a redo record */\n                nk_textedit_discard_redo(s);\n                /* should never happen: */\n                if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT)\n                    return;\n            }\n\n            r = &s->undo_rec[s->redo_point-1];\n            r->char_storage = (short)(s->redo_char_point - u.delete_length);\n            s->redo_char_point = (short)(s->redo_char_point -  u.delete_length);\n\n            /* now save the characters */\n            for (i=0; i < u.delete_length; ++i)\n                s->undo_char[r->char_storage + i] =\n                    nk_str_rune_at(&state->string, u.where + i);\n        }\n        /* now we can carry out the deletion */\n        nk_str_delete_runes(&state->string, u.where, u.delete_length);\n    }\n\n    /* check type of recorded action: */\n    if (u.insert_length) {\n        /* easy case: was a deletion, so we need to insert n characters */\n        nk_str_insert_text_runes(&state->string, u.where,\n            &s->undo_char[u.char_storage], u.insert_length);\n        s->undo_char_point = (short)(s->undo_char_point - u.insert_length);\n    }\n    state->cursor = (short)(u.where + u.insert_length);\n\n    s->undo_point--;\n    s->redo_point--;\n}\nNK_API void\nnk_textedit_redo(struct nk_text_edit *state)\n{\n    struct nk_text_undo_state *s = &state->undo;\n    struct nk_text_undo_record *u, r;\n    if (s->redo_point == NK_TEXTEDIT_UNDOSTATECOUNT)\n        return;\n\n    /* we need to do two things: apply the redo record, and create an undo record */\n    u = &s->undo_rec[s->undo_point];\n    r = s->undo_rec[s->redo_point];\n\n    /* we KNOW there must be room for the undo record, because the redo record\n    was derived from an undo record */\n    u->delete_length = r.insert_length;\n    u->insert_length = r.delete_length;\n    u->where = r.where;\n    u->char_storage = -1;\n\n    if (r.delete_length) {\n        /* the redo record requires us to delete characters, so the undo record\n        needs to store the characters */\n        if (s->undo_char_point + u->insert_length > s->redo_char_point) {\n            u->insert_length = 0;\n            u->delete_length = 0;\n        } else {\n            int i;\n            u->char_storage = s->undo_char_point;\n            s->undo_char_point = (short)(s->undo_char_point + u->insert_length);\n\n            /* now save the characters */\n            for (i=0; i < u->insert_length; ++i) {\n                s->undo_char[u->char_storage + i] =\n                    nk_str_rune_at(&state->string, u->where + i);\n            }\n        }\n        nk_str_delete_runes(&state->string, r.where, r.delete_length);\n    }\n\n    if (r.insert_length) {\n        /* easy case: need to insert n characters */\n        nk_str_insert_text_runes(&state->string, r.where,\n            &s->undo_char[r.char_storage], r.insert_length);\n    }\n    state->cursor = r.where + r.insert_length;\n\n    s->undo_point++;\n    s->redo_point++;\n}\nNK_INTERN void\nnk_textedit_makeundo_insert(struct nk_text_edit *state, int where, int length)\n{\n    nk_textedit_createundo(&state->undo, where, 0, length);\n}\nNK_INTERN void\nnk_textedit_makeundo_delete(struct nk_text_edit *state, int where, int length)\n{\n    int i;\n    nk_rune *p = nk_textedit_createundo(&state->undo, where, length, 0);\n    if (p) {\n        for (i=0; i < length; ++i)\n            p[i] = nk_str_rune_at(&state->string, where+i);\n    }\n}\nNK_INTERN void\nnk_textedit_makeundo_replace(struct nk_text_edit *state, int where,\n    int old_length, int new_length)\n{\n    int i;\n    nk_rune *p = nk_textedit_createundo(&state->undo, where, old_length, new_length);\n    if (p) {\n        for (i=0; i < old_length; ++i)\n            p[i] = nk_str_rune_at(&state->string, where+i);\n    }\n}\nNK_LIB void\nnk_textedit_clear_state(struct nk_text_edit *state, enum nk_text_edit_type type,\n    nk_plugin_filter filter)\n{\n    /* reset the state to default */\n   state->undo.undo_point = 0;\n   state->undo.undo_char_point = 0;\n   state->undo.redo_point = NK_TEXTEDIT_UNDOSTATECOUNT;\n   state->undo.redo_char_point = NK_TEXTEDIT_UNDOCHARCOUNT;\n   state->select_end = state->select_start = 0;\n   state->cursor = 0;\n   state->has_preferred_x = 0;\n   state->preferred_x = 0;\n   state->cursor_at_end_of_line = 0;\n   state->initialized = 1;\n   state->single_line = (unsigned char)(type == NK_TEXT_EDIT_SINGLE_LINE);\n   state->mode = NK_TEXT_EDIT_MODE_VIEW;\n   state->filter = filter;\n   state->scrollbar = nk_vec2(0,0);\n}\nNK_API void\nnk_textedit_init_fixed(struct nk_text_edit *state, void *memory, nk_size size)\n{\n    NK_ASSERT(state);\n    NK_ASSERT(memory);\n    if (!state || !memory || !size) return;\n    NK_MEMSET(state, 0, sizeof(struct nk_text_edit));\n    nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);\n    nk_str_init_fixed(&state->string, memory, size);\n}\nNK_API void\nnk_textedit_init(struct nk_text_edit *state, const struct nk_allocator *alloc, nk_size size)\n{\n    NK_ASSERT(state);\n    NK_ASSERT(alloc);\n    if (!state || !alloc) return;\n    NK_MEMSET(state, 0, sizeof(struct nk_text_edit));\n    nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);\n    nk_str_init(&state->string, alloc, size);\n}\n#ifdef NK_INCLUDE_DEFAULT_ALLOCATOR\nNK_API void\nnk_textedit_init_default(struct nk_text_edit *state)\n{\n    NK_ASSERT(state);\n    if (!state) return;\n    NK_MEMSET(state, 0, sizeof(struct nk_text_edit));\n    nk_textedit_clear_state(state, NK_TEXT_EDIT_SINGLE_LINE, 0);\n    nk_str_init_default(&state->string);\n}\n#endif\nNK_API void\nnk_textedit_select_all(struct nk_text_edit *state)\n{\n    NK_ASSERT(state);\n    state->select_start = 0;\n    state->select_end = state->string.len;\n}\nNK_API void\nnk_textedit_free(struct nk_text_edit *state)\n{\n    NK_ASSERT(state);\n    if (!state) return;\n    nk_str_free(&state->string);\n}\n\n"
  },
  {
    "path": "src/nuklear_toggle.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              TOGGLE\n *\n * ===============================================================*/\nNK_LIB nk_bool\nnk_toggle_behavior(const struct nk_input *in, struct nk_rect select,\n    nk_flags *state, nk_bool active)\n{\n    nk_widget_state_reset(state);\n    if (nk_button_behavior(state, select, in, NK_BUTTON_DEFAULT)) {\n        *state = NK_WIDGET_STATE_ACTIVE;\n        active = !active;\n    }\n    if (*state & NK_WIDGET_STATE_HOVER && !nk_input_is_mouse_prev_hovering_rect(in, select))\n        *state |= NK_WIDGET_STATE_ENTERED;\n    else if (nk_input_is_mouse_prev_hovering_rect(in, select))\n        *state |= NK_WIDGET_STATE_LEFT;\n    return active;\n}\nNK_LIB void\nnk_draw_checkbox(struct nk_command_buffer *out,\n    nk_flags state, const struct nk_style_toggle *style, nk_bool active,\n    const struct nk_rect *label, const struct nk_rect *selector,\n    const struct nk_rect *cursors, const char *string, int len,\n    const struct nk_user_font *font, nk_flags text_alignment)\n{\n    const struct nk_style_item *background;\n    const struct nk_style_item *cursor;\n    struct nk_text text;\n\n    /* select correct colors/images */\n    if (state & NK_WIDGET_STATE_HOVER) {\n        background = &style->hover;\n        cursor = &style->cursor_hover;\n        text.text = style->text_hover;\n    } else if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->hover;\n        cursor = &style->cursor_hover;\n        text.text = style->text_active;\n    } else {\n        background = &style->normal;\n        cursor = &style->cursor_normal;\n        text.text = style->text_normal;\n    }\n\n    text.text = nk_rgb_factor(text.text, style->color_factor);\n    text.padding.x = 0;\n    text.padding.y = 0;\n    text.background = style->text_background;\n    nk_widget_text(out, *label, string, len, &text, text_alignment, font);\n\n    /* draw background and cursor */\n    if (background->type == NK_STYLE_ITEM_COLOR) {\n        nk_fill_rect(out, *selector, 0, nk_rgb_factor(style->border_color, style->color_factor));\n        nk_fill_rect(out, nk_shrink_rect(*selector, style->border), 0, nk_rgb_factor(background->data.color, style->color_factor));\n    } else nk_draw_image(out, *selector, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n    if (active) {\n        if (cursor->type == NK_STYLE_ITEM_IMAGE)\n            nk_draw_image(out, *cursors, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));\n        else nk_fill_rect(out, *cursors, 0, cursor->data.color);\n    }\n}\nNK_LIB void\nnk_draw_option(struct nk_command_buffer *out,\n    nk_flags state, const struct nk_style_toggle *style, nk_bool active,\n    const struct nk_rect *label, const struct nk_rect *selector,\n    const struct nk_rect *cursors, const char *string, int len,\n    const struct nk_user_font *font, nk_flags text_alignment)\n{\n    const struct nk_style_item *background;\n    const struct nk_style_item *cursor;\n    struct nk_text text;\n\n    /* select correct colors/images */\n    if (state & NK_WIDGET_STATE_HOVER) {\n        background = &style->hover;\n        cursor = &style->cursor_hover;\n        text.text = style->text_hover;\n    } else if (state & NK_WIDGET_STATE_ACTIVED) {\n        background = &style->hover;\n        cursor = &style->cursor_hover;\n        text.text = style->text_active;\n    } else {\n        background = &style->normal;\n        cursor = &style->cursor_normal;\n        text.text = style->text_normal;\n    }\n\n    text.text = nk_rgb_factor(text.text, style->color_factor);\n    text.padding.x = 0;\n    text.padding.y = 0;\n    text.background = style->text_background;\n    nk_widget_text(out, *label, string, len, &text, text_alignment, font);\n\n    /* draw background and cursor */\n    if (background->type == NK_STYLE_ITEM_COLOR) {\n        nk_fill_circle(out, *selector, nk_rgb_factor(style->border_color, style->color_factor));\n        nk_fill_circle(out, nk_shrink_rect(*selector, style->border), nk_rgb_factor(background->data.color, style->color_factor));\n    } else nk_draw_image(out, *selector, &background->data.image, nk_rgb_factor(nk_white, style->color_factor));\n    if (active) {\n        if (cursor->type == NK_STYLE_ITEM_IMAGE)\n            nk_draw_image(out, *cursors, &cursor->data.image, nk_rgb_factor(nk_white, style->color_factor));\n        else nk_fill_circle(out, *cursors, cursor->data.color);\n    }\n}\nNK_LIB nk_bool\nnk_do_toggle(nk_flags *state,\n    struct nk_command_buffer *out, struct nk_rect r,\n    nk_bool *active, const char *str, int len, enum nk_toggle_type type,\n    const struct nk_style_toggle *style, const struct nk_input *in,\n    const struct nk_user_font *font, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    int was_active;\n    struct nk_rect bounds;\n    struct nk_rect select;\n    struct nk_rect cursor;\n    struct nk_rect label;\n\n    NK_ASSERT(style);\n    NK_ASSERT(out);\n    NK_ASSERT(font);\n    if (!out || !style || !font || !active)\n        return 0;\n\n    r.w = NK_MAX(r.w, font->height + 2 * style->padding.x);\n    r.h = NK_MAX(r.h, font->height + 2 * style->padding.y);\n\n    /* add additional touch padding for touch screen devices */\n    bounds.x = r.x - style->touch_padding.x;\n    bounds.y = r.y - style->touch_padding.y;\n    bounds.w = r.w + 2 * style->touch_padding.x;\n    bounds.h = r.h + 2 * style->touch_padding.y;\n\n    /* calculate the selector space */\n    select.w = font->height;\n    select.h = select.w;\n\n    if (widget_alignment & NK_WIDGET_ALIGN_RIGHT) {\n        select.x = r.x + r.w - font->height;\n\n        /* label in front of the selector */\n        label.x = r.x;\n        label.w = r.w - select.w - style->spacing * 2;\n    } else if (widget_alignment & NK_WIDGET_ALIGN_CENTERED) {\n        select.x = r.x + (r.w - select.w) / 2;\n\n        /* label in front of selector */\n        label.x = r.x;\n        label.w = (r.w - select.w - style->spacing * 2) / 2;\n    } else { /* Default: NK_WIDGET_ALIGN_LEFT */\n        select.x = r.x;\n\n        /* label behind the selector */\n        label.x = select.x + select.w + style->spacing;\n        label.w = NK_MAX(r.x + r.w, label.x) - label.x;\n    }\n\n    if (widget_alignment & NK_WIDGET_ALIGN_TOP) {\n        select.y = r.y;\n    } else if (widget_alignment & NK_WIDGET_ALIGN_BOTTOM) {\n        select.y = r.y + r.h - select.h - 2 * style->padding.y;\n    } else { /* Default: NK_WIDGET_ALIGN_MIDDLE */\n        select.y = r.y + r.h/2.0f - select.h/2.0f;\n    }\n\n    label.y = select.y;\n    label.h = select.w;\n\n    /* calculate the bounds of the cursor inside the selector */\n    cursor.x = select.x + style->padding.x + style->border;\n    cursor.y = select.y + style->padding.y + style->border;\n    cursor.w = select.w - (2 * style->padding.x + 2 * style->border);\n    cursor.h = select.h - (2 * style->padding.y + 2 * style->border);\n\n    /* update selector */\n    was_active = *active;\n    *active = nk_toggle_behavior(in, bounds, state, *active);\n\n    /* draw selector */\n    if (style->draw_begin)\n        style->draw_begin(out, style->userdata);\n    if (type == NK_TOGGLE_CHECK) {\n        nk_draw_checkbox(out, *state, style, *active, &label, &select, &cursor, str, len, font, text_alignment);\n    } else {\n        nk_draw_option(out, *state, style, *active, &label, &select, &cursor, str, len, font, text_alignment);\n    }\n    if (style->draw_end)\n        style->draw_end(out, style->userdata);\n    return (was_active != *active);\n}\n/*----------------------------------------------------------------\n *\n *                          CHECKBOX\n *\n * --------------------------------------------------------------*/\nNK_API nk_bool\nnk_check_text(struct nk_context *ctx, const char *text, int len, nk_bool active)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return active;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return active;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active,\n        text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font, NK_WIDGET_LEFT, NK_TEXT_LEFT);\n    return active;\n}\nNK_API nk_bool\nnk_check_text_align(struct nk_context *ctx, const char *text, int len, nk_bool active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return active;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return active;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &active,\n        text, len, NK_TOGGLE_CHECK, &style->checkbox, in, style->font, widget_alignment, text_alignment);\n    return active;\n}\nNK_API unsigned int\nnk_check_flags_text(struct nk_context *ctx, const char *text, int len,\n    unsigned int flags, unsigned int value)\n{\n    int old_active;\n    NK_ASSERT(ctx);\n    NK_ASSERT(text);\n    if (!ctx || !text) return flags;\n    old_active = (int)((flags & value) & value);\n    if (nk_check_text(ctx, text, len, old_active))\n        flags |= value;\n    else flags &= ~value;\n    return flags;\n}\nNK_API nk_bool\nnk_checkbox_text(struct nk_context *ctx, const char *text, int len, nk_bool *active)\n{\n    int old_val;\n    NK_ASSERT(ctx);\n    NK_ASSERT(text);\n    NK_ASSERT(active);\n    if (!ctx || !text || !active) return 0;\n    old_val = *active;\n    *active = nk_check_text(ctx, text, len, *active);\n    return old_val != *active;\n}\nNK_API nk_bool\nnk_checkbox_text_align(struct nk_context *ctx, const char *text, int len, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    int old_val;\n    NK_ASSERT(ctx);\n    NK_ASSERT(text);\n    NK_ASSERT(active);\n    if (!ctx || !text || !active) return 0;\n    old_val = *active;\n    *active = nk_check_text_align(ctx, text, len, *active, widget_alignment, text_alignment);\n    return old_val != *active;\n}\nNK_API nk_bool\nnk_checkbox_flags_text(struct nk_context *ctx, const char *text, int len,\n    unsigned int *flags, unsigned int value)\n{\n    nk_bool active;\n    NK_ASSERT(ctx);\n    NK_ASSERT(text);\n    NK_ASSERT(flags);\n    if (!ctx || !text || !flags) return 0;\n\n    active = (int)((*flags & value) & value);\n    if (nk_checkbox_text(ctx, text, len, &active)) {\n        if (active) *flags |= value;\n        else *flags &= ~value;\n        return 1;\n    }\n    return 0;\n}\nNK_API nk_bool nk_check_label(struct nk_context *ctx, const char *label, nk_bool active)\n{\n    return nk_check_text(ctx, label, nk_strlen(label), active);\n}\nNK_API unsigned int nk_check_flags_label(struct nk_context *ctx, const char *label,\n    unsigned int flags, unsigned int value)\n{\n    return nk_check_flags_text(ctx, label, nk_strlen(label), flags, value);\n}\nNK_API nk_bool nk_checkbox_label(struct nk_context *ctx, const char *label, nk_bool *active)\n{\n    return nk_checkbox_text(ctx, label, nk_strlen(label), active);\n}\nNK_API nk_bool nk_checkbox_label_align(struct nk_context *ctx, const char *label, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    return nk_checkbox_text_align(ctx, label, nk_strlen(label), active, widget_alignment, text_alignment);\n}\nNK_API nk_bool nk_checkbox_flags_label(struct nk_context *ctx, const char *label,\n    unsigned int *flags, unsigned int value)\n{\n    return nk_checkbox_flags_text(ctx, label, nk_strlen(label), flags, value);\n}\n/*----------------------------------------------------------------\n *\n *                          OPTION\n *\n * --------------------------------------------------------------*/\nNK_API nk_bool\nnk_option_text(struct nk_context *ctx, const char *text, int len, nk_bool is_active)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return is_active;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return (int)state;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active,\n        text, len, NK_TOGGLE_OPTION, &style->option, in, style->font, NK_WIDGET_LEFT, NK_TEXT_LEFT);\n    return is_active;\n}\nNK_API nk_bool\nnk_option_text_align(struct nk_context *ctx, const char *text, int len, nk_bool is_active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n    const struct nk_style *style;\n\n    struct nk_rect bounds;\n    enum nk_widget_layout_states state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return is_active;\n\n    win = ctx->current;\n    style = &ctx->style;\n    layout = win->layout;\n\n    state = nk_widget(&bounds, ctx);\n    if (!state) return (int)state;\n    in = (state == NK_WIDGET_ROM || state == NK_WIDGET_DISABLED || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;\n    nk_do_toggle(&ctx->last_widget_state, &win->buffer, bounds, &is_active,\n        text, len, NK_TOGGLE_OPTION, &style->option, in, style->font, widget_alignment, text_alignment);\n    return is_active;\n}\nNK_API nk_bool\nnk_radio_text(struct nk_context *ctx, const char *text, int len, nk_bool *active)\n{\n    int old_value;\n    NK_ASSERT(ctx);\n    NK_ASSERT(text);\n    NK_ASSERT(active);\n    if (!ctx || !text || !active) return 0;\n    old_value = *active;\n    *active = nk_option_text(ctx, text, len, old_value);\n    return old_value != *active;\n}\nNK_API nk_bool\nnk_radio_text_align(struct nk_context *ctx, const char *text, int len, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    int old_value;\n    NK_ASSERT(ctx);\n    NK_ASSERT(text);\n    NK_ASSERT(active);\n    if (!ctx || !text || !active) return 0;\n    old_value = *active;\n    *active = nk_option_text_align(ctx, text, len, old_value, widget_alignment, text_alignment);\n    return old_value != *active;\n}\nNK_API nk_bool\nnk_option_label(struct nk_context *ctx, const char *label, nk_bool active)\n{\n    return nk_option_text(ctx, label, nk_strlen(label), active);\n}\nNK_API nk_bool\nnk_option_label_align(struct nk_context *ctx, const char *label, nk_bool active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    return nk_option_text_align(ctx, label, nk_strlen(label), active, widget_alignment, text_alignment);\n}\nNK_API nk_bool\nnk_radio_label(struct nk_context *ctx, const char *label, nk_bool *active)\n{\n    return nk_radio_text(ctx, label, nk_strlen(label), active);\n}\nNK_API nk_bool\nnk_radio_label_align(struct nk_context *ctx, const char *label, nk_bool *active, nk_flags widget_alignment, nk_flags text_alignment)\n{\n    return nk_radio_text_align(ctx, label, nk_strlen(label), active, widget_alignment, text_alignment);\n}\n\n"
  },
  {
    "path": "src/nuklear_tooltip.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              TOOLTIP\n *\n * ===============================================================*/\nNK_API nk_bool\nnk_tooltip_begin(struct nk_context *ctx, float width)\n{\n    NK_ASSERT(ctx);\n    return nk_tooltip_begin_offset(ctx, width, ctx->style.window.tooltip_origin, ctx->style.window.tooltip_offset);\n}\n\nNK_API nk_bool\nnk_tooltip_begin_offset(struct nk_context *ctx, float width, enum nk_tooltip_pos position, struct nk_vec2 offset)\n{\n    int x,y,w,h;\n    struct nk_window *win;\n    const struct nk_input *in;\n    struct nk_rect bounds;\n    int ret;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    /* make sure that no nonblocking popup is currently active */\n    win = ctx->current;\n    in = &ctx->input;\n    if (win->popup.win && ((int)win->popup.type & (int)NK_PANEL_SET_NONBLOCK))\n        return 0;\n\n    w = nk_iceilf(width);\n    h = NK_MAX(win->layout->row.min_height, ctx->style.font->height+2*ctx->style.window.padding.y);\n\n    /* Default origin is top left, plus user offset */\n    x = nk_ifloorf(in->mouse.pos.x + 1) - (int)win->layout->clip.x + offset.x;\n    y = nk_ifloorf(in->mouse.pos.y + 1) - (int)win->layout->clip.y + offset.y;\n\n    /* Adjust origin based on enum */\n    switch (position) {\n    case NK_TOP_LEFT:\n        /* no change */\n        break;\n    case NK_TOP_CENTER:\n        x -= w/2;\n        break;\n    case NK_TOP_RIGHT:\n        x -= w;\n        break;\n\n    case NK_MIDDLE_LEFT:\n        y -= h/2;\n        break;\n    case NK_MIDDLE_CENTER:\n        x -= w/2;\n        y -= h/2;\n        break;\n    case NK_MIDDLE_RIGHT:\n        x -= w;\n        y -= h/2;\n        break;\n\n    case NK_BOTTOM_LEFT:\n        y -= h;\n        break;\n    case NK_BOTTOM_CENTER:\n        x -= w/2;\n        y -= h;\n        break;\n    case NK_BOTTOM_RIGHT:\n        x -= w;\n        y -= h;\n        break;\n    default:\n        NK_ASSERT(0 && \"Invalid tooltip position\");\n    }\n\n    bounds.x = (float)x;\n    bounds.y = (float)y;\n    bounds.w = (float)w;\n    bounds.h = (float)nk_iceilf(nk_null_rect.h);\n\n    ret = nk_popup_begin(ctx, NK_POPUP_DYNAMIC,\n        \"__##Tooltip##__\", NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_BORDER, bounds);\n    if (ret) win->layout->flags &= ~(nk_flags)NK_WINDOW_ROM;\n    win->popup.type = NK_PANEL_TOOLTIP;\n    ctx->current->layout->type = NK_PANEL_TOOLTIP;\n    return ret;\n}\n\nNK_API void\nnk_tooltip_end(struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return;\n    ctx->current->seq--;\n    nk_popup_close(ctx);\n    nk_popup_end(ctx);\n}\n\nNK_API void\nnk_tooltip_offset(struct nk_context *ctx, const char *text, enum nk_tooltip_pos position, struct nk_vec2 offset)\n{\n    const struct nk_style *style;\n    struct nk_vec2 padding;\n\n    int text_len;\n    float text_width;\n    float text_height;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    NK_ASSERT(text);\n    if (!ctx || !ctx->current || !ctx->current->layout || !text)\n        return;\n\n    /* fetch configuration data */\n    style = &ctx->style;\n    padding = style->window.padding;\n\n    /* calculate size of the text and tooltip */\n    text_len = nk_strlen(text);\n    text_width = style->font->width(style->font->userdata,\n                    style->font->height, text, text_len);\n    text_width += (4 * padding.x);\n    text_height = (style->font->height + 2 * padding.y);\n\n    /* execute tooltip and fill with text */\n    if (nk_tooltip_begin_offset(ctx, (float)text_width, position, offset)) {\n        nk_layout_row_dynamic(ctx, (float)text_height, 1);\n        nk_text(ctx, text, text_len, NK_TEXT_LEFT);\n        nk_tooltip_end(ctx);\n    }\n}\n\nNK_API void\nnk_tooltip(struct nk_context *ctx, const char *text)\n{\n    NK_ASSERT(ctx);\n    nk_tooltip_offset(ctx, text, ctx->style.window.tooltip_origin, ctx->style.window.tooltip_offset);\n}\n#ifdef NK_INCLUDE_STANDARD_VARARGS\nNK_API void\nnk_tooltipf_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    nk_tooltipfv_offset(ctx, position, offset, fmt, args);\n    va_end(args);\n}\nNK_API void\nnk_tooltipf(struct nk_context *ctx, const char *fmt, ...)\n{\n    va_list args;\n    va_start(args, fmt);\n    nk_tooltipfv(ctx, fmt, args);\n    va_end(args);\n}\nNK_API void\nnk_tooltipfv_offset(struct nk_context *ctx, enum nk_tooltip_pos position, struct nk_vec2 offset, const char *fmt, va_list args)\n{\n    char buf[256];\n    nk_strfmt(buf, NK_LEN(buf), fmt, args);\n    nk_tooltip_offset(ctx, buf, position, offset);\n}\nNK_API void\nnk_tooltipfv(struct nk_context *ctx, const char *fmt, va_list args)\n{\n    char buf[256];\n    nk_strfmt(buf, NK_LEN(buf), fmt, args);\n    nk_tooltip(ctx, buf);\n}\n#endif\n\n\n"
  },
  {
    "path": "src/nuklear_tree.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              TREE\n *\n * ===============================================================*/\nNK_INTERN int\nnk_tree_state_base(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image *img, const char *title, enum nk_collapse_states *state)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_style *style;\n    struct nk_command_buffer *out;\n    const struct nk_input *in;\n    const struct nk_style_button *button;\n    enum nk_symbol_type symbol;\n    float row_height;\n\n    struct nk_vec2 item_spacing;\n    struct nk_rect header = {0,0,0,0};\n    struct nk_rect sym = {0,0,0,0};\n    struct nk_text text;\n\n    nk_flags ws = 0;\n    enum nk_widget_layout_states widget_state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    /* cache some data */\n    win = ctx->current;\n    layout = win->layout;\n    out = &win->buffer;\n    style = &ctx->style;\n    item_spacing = style->window.spacing;\n\n    /* calculate header bounds and draw background */\n    row_height = style->font->height + 2 * style->tab.padding.y;\n    nk_layout_set_min_row_height(ctx, row_height);\n    nk_layout_row_dynamic(ctx, row_height, 1);\n    nk_layout_reset_min_row_height(ctx);\n\n    widget_state = nk_widget(&header, ctx);\n    if (type == NK_TREE_TAB) {\n        const struct nk_style_item *background = &style->tab.background;\n\n        switch(background->type) {\n            case NK_STYLE_ITEM_IMAGE:\n                nk_draw_image(out, header, &background->data.image, nk_rgb_factor(nk_white, style->tab.color_factor));\n                break;\n            case NK_STYLE_ITEM_NINE_SLICE:\n                nk_draw_nine_slice(out, header, &background->data.slice, nk_rgb_factor(nk_white, style->tab.color_factor));\n                break;\n            case NK_STYLE_ITEM_COLOR:\n                nk_fill_rect(out, header, 0, nk_rgb_factor(style->tab.border_color, style->tab.color_factor));\n                nk_fill_rect(out, nk_shrink_rect(header, style->tab.border),\n                    style->tab.rounding, nk_rgb_factor(background->data.color, style->tab.color_factor));\n                break;\n        }\n    } else text.background = style->window.background;\n\n    /* update node state */\n    in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0;\n    in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0;\n    if (nk_button_behavior(&ws, header, in, NK_BUTTON_DEFAULT))\n        *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;\n\n    /* select correct button style */\n    if (*state == NK_MAXIMIZED) {\n        symbol = style->tab.sym_maximize;\n        if (type == NK_TREE_TAB)\n            button = &style->tab.tab_maximize_button;\n        else button = &style->tab.node_maximize_button;\n    } else {\n        symbol = style->tab.sym_minimize;\n        if (type == NK_TREE_TAB)\n            button = &style->tab.tab_minimize_button;\n        else button = &style->tab.node_minimize_button;\n    }\n\n    {/* draw triangle button */\n    sym.w = sym.h = style->font->height;\n    sym.y = header.y + style->tab.padding.y;\n    sym.x = header.x + style->tab.padding.x;\n    nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT,\n        button, 0, style->font);\n\n    if (img) {\n        /* draw optional image icon */\n        sym.x = sym.x + sym.w + 4 * item_spacing.x;\n        nk_draw_image(&win->buffer, sym, img, nk_white);\n        sym.w = style->font->height + style->tab.spacing.x;}\n    }\n\n    {/* draw label */\n    struct nk_rect label;\n    header.w = NK_MAX(header.w, sym.w + item_spacing.x);\n    label.x = sym.x + sym.w + item_spacing.x;\n    label.y = sym.y;\n    label.w = header.w - (sym.w + item_spacing.y + style->tab.indent);\n    label.h = style->font->height;\n    text.text = nk_rgb_factor(style->tab.text, style->tab.color_factor);\n    text.padding = nk_vec2(0,0);\n    nk_widget_text(out, label, title, nk_strlen(title), &text,\n        NK_TEXT_LEFT, style->font);}\n\n    /* increase x-axis cursor widget position pointer */\n    if (*state == NK_MAXIMIZED) {\n        layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent;\n        layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent);\n        layout->bounds.w -= (style->tab.indent + style->window.padding.x);\n        layout->row.tree_depth++;\n        return nk_true;\n    } else return nk_false;\n}\nNK_INTERN int\nnk_tree_base(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image *img, const char *title, enum nk_collapse_states initial_state,\n    const char *hash, int len, int line)\n{\n    struct nk_window *win = ctx->current;\n    int title_len = 0;\n    nk_hash tree_hash = 0;\n    nk_uint *state = 0;\n\n    /* retrieve tree state from internal widget state tables */\n    if (!hash) {\n        title_len = (int)nk_strlen(title);\n        tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line);\n    } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line);\n    state = nk_find_value(win, tree_hash);\n    if (!state) {\n        state = nk_add_value(ctx, win, tree_hash, 0);\n        *state = initial_state;\n    }\n    return nk_tree_state_base(ctx, type, img, title, (enum nk_collapse_states*)state);\n}\nNK_API nk_bool\nnk_tree_state_push(struct nk_context *ctx, enum nk_tree_type type,\n    const char *title, enum nk_collapse_states *state)\n{\n    return nk_tree_state_base(ctx, type, 0, title, state);\n}\nNK_API nk_bool\nnk_tree_state_image_push(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image img, const char *title, enum nk_collapse_states *state)\n{\n    return nk_tree_state_base(ctx, type, &img, title, state);\n}\nNK_API void\nnk_tree_state_pop(struct nk_context *ctx)\n{\n    struct nk_window *win = 0;\n    struct nk_panel *layout = 0;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    win = ctx->current;\n    layout = win->layout;\n    layout->at_x -= ctx->style.tab.indent + (float)*layout->offset_x;\n    layout->bounds.w += ctx->style.tab.indent + ctx->style.window.padding.x;\n    NK_ASSERT(layout->row.tree_depth);\n    layout->row.tree_depth--;\n}\nNK_API nk_bool\nnk_tree_push_hashed(struct nk_context *ctx, enum nk_tree_type type,\n    const char *title, enum nk_collapse_states initial_state,\n    const char *hash, int len, int line)\n{\n    return nk_tree_base(ctx, type, 0, title, initial_state, hash, len, line);\n}\nNK_API nk_bool\nnk_tree_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image img, const char *title, enum nk_collapse_states initial_state,\n    const char *hash, int len,int seed)\n{\n    return nk_tree_base(ctx, type, &img, title, initial_state, hash, len, seed);\n}\nNK_API void\nnk_tree_pop(struct nk_context *ctx)\n{\n    nk_tree_state_pop(ctx);\n}\nNK_INTERN int\nnk_tree_element_image_push_hashed_base(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image *img, const char *title, int title_len,\n    enum nk_collapse_states *state, nk_bool *selected)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_style *style;\n    struct nk_command_buffer *out;\n    const struct nk_input *in;\n    const struct nk_style_button *button;\n    enum nk_symbol_type symbol;\n    float row_height;\n    struct nk_vec2 padding;\n\n    int text_len;\n    float text_width;\n\n    struct nk_vec2 item_spacing;\n    struct nk_rect header = {0,0,0,0};\n    struct nk_rect sym = {0,0,0,0};\n\n    nk_flags ws = 0;\n    enum nk_widget_layout_states widget_state;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return 0;\n\n    /* cache some data */\n    win = ctx->current;\n    layout = win->layout;\n    out = &win->buffer;\n    style = &ctx->style;\n    item_spacing = style->window.spacing;\n    padding = style->selectable.padding;\n\n    /* calculate header bounds and draw background */\n    row_height = style->font->height + 2 * style->tab.padding.y;\n    nk_layout_set_min_row_height(ctx, row_height);\n    nk_layout_row_dynamic(ctx, row_height, 1);\n    nk_layout_reset_min_row_height(ctx);\n\n    widget_state = nk_widget(&header, ctx);\n    if (type == NK_TREE_TAB) {\n        const struct nk_style_item *background = &style->tab.background;\n\n        switch (background->type) {\n            case NK_STYLE_ITEM_IMAGE:\n                nk_draw_image(out, header, &background->data.image, nk_rgb_factor(nk_white, style->tab.color_factor));\n                break;\n            case NK_STYLE_ITEM_NINE_SLICE:\n                nk_draw_nine_slice(out, header, &background->data.slice, nk_rgb_factor(nk_white, style->tab.color_factor));\n                break;\n            case NK_STYLE_ITEM_COLOR:\n                nk_fill_rect(out, header, 0, nk_rgb_factor(style->tab.border_color, style->tab.color_factor));\n                nk_fill_rect(out, nk_shrink_rect(header, style->tab.border),\n                    style->tab.rounding, nk_rgb_factor(background->data.color, style->tab.color_factor));\n\n                break;\n        }\n    }\n\n    in = (!(layout->flags & NK_WINDOW_ROM)) ? &ctx->input: 0;\n    in = (in && widget_state == NK_WIDGET_VALID) ? &ctx->input : 0;\n\n    /* select correct button style */\n    if (*state == NK_MAXIMIZED) {\n        symbol = style->tab.sym_maximize;\n        if (type == NK_TREE_TAB)\n            button = &style->tab.tab_maximize_button;\n        else button = &style->tab.node_maximize_button;\n    } else {\n        symbol = style->tab.sym_minimize;\n        if (type == NK_TREE_TAB)\n            button = &style->tab.tab_minimize_button;\n        else button = &style->tab.node_minimize_button;\n    }\n    {/* draw triangle button */\n    sym.w = sym.h = style->font->height;\n    sym.y = header.y + style->tab.padding.y;\n    sym.x = header.x + style->tab.padding.x;\n    if (nk_do_button_symbol(&ws, &win->buffer, sym, symbol, NK_BUTTON_DEFAULT, button, in, style->font))\n        *state = (*state == NK_MAXIMIZED) ? NK_MINIMIZED : NK_MAXIMIZED;}\n\n    /* draw label */\n    {nk_flags dummy = 0;\n    struct nk_rect label;\n    /* calculate size of the text and tooltip */\n    text_len = nk_strlen(title);\n    text_width = style->font->width(style->font->userdata, style->font->height, title, text_len);\n    text_width += (4 * padding.x);\n\n    header.w = NK_MAX(header.w, sym.w + item_spacing.x);\n    label.x = sym.x + sym.w + item_spacing.x;\n    label.y = sym.y;\n    label.w = NK_MIN(header.w - (sym.w + item_spacing.y + style->tab.indent), text_width);\n    label.h = style->font->height;\n\n    if (img) {\n        nk_do_selectable_image(&dummy, &win->buffer, label, title, title_len, NK_TEXT_LEFT,\n            selected, img, &style->selectable, in, style->font);\n    } else nk_do_selectable(&dummy, &win->buffer, label, title, title_len, NK_TEXT_LEFT,\n            selected, &style->selectable, in, style->font);\n    }\n    /* increase x-axis cursor widget position pointer */\n    if (*state == NK_MAXIMIZED) {\n        layout->at_x = header.x + (float)*layout->offset_x + style->tab.indent;\n        layout->bounds.w = NK_MAX(layout->bounds.w, style->tab.indent);\n        layout->bounds.w -= (style->tab.indent + style->window.padding.x);\n        layout->row.tree_depth++;\n        return nk_true;\n    } else return nk_false;\n}\nNK_INTERN int\nnk_tree_element_base(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image *img, const char *title, enum nk_collapse_states initial_state,\n    nk_bool *selected, const char *hash, int len, int line)\n{\n    struct nk_window *win = ctx->current;\n    int title_len = 0;\n    nk_hash tree_hash = 0;\n    nk_uint *state = 0;\n\n    /* retrieve tree state from internal widget state tables */\n    if (!hash) {\n        title_len = (int)nk_strlen(title);\n        tree_hash = nk_murmur_hash(title, (int)title_len, (nk_hash)line);\n    } else tree_hash = nk_murmur_hash(hash, len, (nk_hash)line);\n    state = nk_find_value(win, tree_hash);\n    if (!state) {\n        state = nk_add_value(ctx, win, tree_hash, 0);\n        *state = initial_state;\n    } return nk_tree_element_image_push_hashed_base(ctx, type, img, title,\n        nk_strlen(title), (enum nk_collapse_states*)state, selected);\n}\nNK_API nk_bool\nnk_tree_element_push_hashed(struct nk_context *ctx, enum nk_tree_type type,\n    const char *title, enum nk_collapse_states initial_state,\n    nk_bool *selected, const char *hash, int len, int seed)\n{\n    return nk_tree_element_base(ctx, type, 0, title, initial_state, selected, hash, len, seed);\n}\nNK_API nk_bool\nnk_tree_element_image_push_hashed(struct nk_context *ctx, enum nk_tree_type type,\n    struct nk_image img, const char *title, enum nk_collapse_states initial_state,\n    nk_bool *selected, const char *hash, int len,int seed)\n{\n    return nk_tree_element_base(ctx, type, &img, title, initial_state, selected, hash, len, seed);\n}\nNK_API void\nnk_tree_element_pop(struct nk_context *ctx)\n{\n    nk_tree_state_pop(ctx);\n}\n\n"
  },
  {
    "path": "src/nuklear_utf8.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              UTF-8\n *\n * ===============================================================*/\nNK_GLOBAL const nk_byte nk_utfbyte[NK_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0};\nNK_GLOBAL const nk_byte nk_utfmask[NK_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};\nNK_GLOBAL const nk_uint nk_utfmin[NK_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x10000};\nNK_GLOBAL const nk_uint nk_utfmax[NK_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};\n\nNK_INTERN int\nnk_utf_validate(nk_rune *u, int i)\n{\n    NK_ASSERT(u);\n    if (!u) return 0;\n    if (!NK_BETWEEN(*u, nk_utfmin[i], nk_utfmax[i]) ||\n         NK_BETWEEN(*u, 0xD800, 0xDFFF))\n            *u = NK_UTF_INVALID;\n    for (i = 1; *u > nk_utfmax[i]; ++i);\n    return i;\n}\nNK_INTERN nk_rune\nnk_utf_decode_byte(char c, int *i)\n{\n    NK_ASSERT(i);\n    if (!i) return 0;\n    for(*i = 0; *i < (int)NK_LEN(nk_utfmask); ++(*i)) {\n        if (((nk_byte)c & nk_utfmask[*i]) == nk_utfbyte[*i])\n            return (nk_byte)(c & ~nk_utfmask[*i]);\n    }\n    return 0;\n}\nNK_API int\nnk_utf_decode(const char *c, nk_rune *u, int clen)\n{\n    int i, j, len, type=0;\n    nk_rune udecoded;\n\n    NK_ASSERT(c);\n    NK_ASSERT(u);\n\n    if (!c || !u) return 0;\n    if (!clen) return 0;\n    *u = NK_UTF_INVALID;\n\n    udecoded = nk_utf_decode_byte(c[0], &len);\n    if (!NK_BETWEEN(len, 1, NK_UTF_SIZE+1)) /* +1 because NK_BETWEEN uses strict upper bound ((a) <= (x) && (x) < (b)) */\n        return 1;\n\n    for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {\n        udecoded = (udecoded << 6) | nk_utf_decode_byte(c[i], &type);\n        if (type != 0)\n            return j;\n    }\n    if (j < len)\n        return 0;\n    *u = udecoded;\n    nk_utf_validate(u, len);\n    return len;\n}\nNK_INTERN char\nnk_utf_encode_byte(nk_rune u, int i)\n{\n    return (char)((nk_utfbyte[i]) | ((nk_byte)u & ~nk_utfmask[i]));\n}\nNK_API int\nnk_utf_encode(nk_rune u, char *c, int clen)\n{\n    int len, i;\n    len = nk_utf_validate(&u, 0);\n    if (clen < len || !len || len > NK_UTF_SIZE)\n        return 0;\n\n    for (i = len - 1; i != 0; --i) {\n        c[i] = nk_utf_encode_byte(u, 0);\n        u >>= 6;\n    }\n    c[0] = nk_utf_encode_byte(u, len);\n    return len;\n}\nNK_API int\nnk_utf_len(const char *str, int len)\n{\n    const char *text;\n    int glyphs = 0;\n    int text_len;\n    int glyph_len;\n    int src_len = 0;\n    nk_rune unicode;\n\n    NK_ASSERT(str);\n    if (!str || !len) return 0;\n\n    text = str;\n    text_len = len;\n    glyph_len = nk_utf_decode(text, &unicode, text_len);\n    while (glyph_len && src_len < len) {\n        glyphs++;\n        src_len = src_len + glyph_len;\n        glyph_len = nk_utf_decode(text + src_len, &unicode, text_len - src_len);\n    }\n    return glyphs;\n}\nNK_API const char*\nnk_utf_at(const char *buffer, int length, int index,\n    nk_rune *unicode, int *len)\n{\n    int i = 0;\n    int src_len = 0;\n    int glyph_len = 0;\n    const char *text;\n    int text_len;\n\n    NK_ASSERT(buffer);\n    NK_ASSERT(unicode);\n    NK_ASSERT(len);\n\n    if (!buffer || !unicode || !len) return 0;\n    if (index < 0) {\n        *unicode = NK_UTF_INVALID;\n        *len = 0;\n        return 0;\n    }\n\n    text = buffer;\n    text_len = length;\n    glyph_len = nk_utf_decode(text, unicode, text_len);\n    while (glyph_len) {\n        if (i == index) {\n            *len = glyph_len;\n            break;\n        }\n\n        i++;\n        src_len = src_len + glyph_len;\n        glyph_len = nk_utf_decode(text + src_len, unicode, text_len - src_len);\n    }\n    if (i != index) return 0;\n    return buffer + src_len;\n}\n\n"
  },
  {
    "path": "src/nuklear_util.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              UTIL\n *\n * ===============================================================*/\nNK_INTERN int nk_str_match_here(const char *regexp, const char *text);\nNK_INTERN int nk_str_match_star(int c, const char *regexp, const char *text);\nNK_LIB nk_bool nk_is_lower(int c) {return (c >= 'a' && c <= 'z') || (c >= 0xE0 && c <= 0xFF);}\nNK_LIB nk_bool nk_is_upper(int c){return (c >= 'A' && c <= 'Z') || (c >= 0xC0 && c <= 0xDF);}\nNK_LIB int nk_to_upper(int c) {return (c >= 'a' && c <= 'z') ? (c - ('a' - 'A')) : c;}\nNK_LIB int nk_to_lower(int c) {return (c >= 'A' && c <= 'Z') ? (c - ('a' + 'A')) : c;}\n\n#ifdef NK_MEMCPY_NEEDED\nNK_LIB void*\nnk_memcopy(void *dst0, const void *src0, nk_size length)\n{\n    nk_ptr t;\n    char *dst = (char*)dst0;\n    const char *src = (const char*)src0;\n    if (length == 0 || dst == src)\n        goto done;\n\n    #define nk_word int\n    #define nk_wsize sizeof(nk_word)\n    #define nk_wmask (nk_wsize-1)\n    #define NK_TLOOP(s) if (t) NK_TLOOP1(s)\n    #define NK_TLOOP1(s) do { s; } while (--t)\n\n    if (dst < src) {\n        t = (nk_ptr)src; /* only need low bits */\n        if ((t | (nk_ptr)dst) & nk_wmask) {\n            if ((t ^ (nk_ptr)dst) & nk_wmask || length < nk_wsize)\n                t = length;\n            else\n                t = nk_wsize - (t & nk_wmask);\n            length -= t;\n            NK_TLOOP1(*dst++ = *src++);\n        }\n        t = length / nk_wsize;\n        NK_TLOOP(*(nk_word*)(void*)dst = *(const nk_word*)(const void*)src;\n            src += nk_wsize; dst += nk_wsize);\n        t = length & nk_wmask;\n        NK_TLOOP(*dst++ = *src++);\n    } else {\n        src += length;\n        dst += length;\n        t = (nk_ptr)src;\n        if ((t | (nk_ptr)dst) & nk_wmask) {\n            if ((t ^ (nk_ptr)dst) & nk_wmask || length <= nk_wsize)\n                t = length;\n            else\n                t &= nk_wmask;\n            length -= t;\n            NK_TLOOP1(*--dst = *--src);\n        }\n        t = length / nk_wsize;\n        NK_TLOOP(src -= nk_wsize; dst -= nk_wsize;\n            *(nk_word*)(void*)dst = *(const nk_word*)(const void*)src);\n        t = length & nk_wmask;\n        NK_TLOOP(*--dst = *--src);\n    }\n    #undef nk_word\n    #undef nk_wsize\n    #undef nk_wmask\n    #undef NK_TLOOP\n    #undef NK_TLOOP1\ndone:\n    return (dst0);\n}\n#endif\n#ifdef NK_MEMSET_NEEDED\nNK_LIB void\nnk_memset(void *ptr, int c0, nk_size size)\n{\n    #define nk_word unsigned\n    #define nk_wsize sizeof(nk_word)\n    #define nk_wmask (nk_wsize - 1)\n    nk_byte *dst = (nk_byte*)ptr;\n    unsigned c = 0;\n    nk_size t = 0;\n\n    if ((c = (nk_byte)c0) != 0) {\n        c = (c << 8) | c; /* at least 16-bits  */\n        if (sizeof(unsigned int) > 2)\n            c = (c << 16) | c; /* at least 32-bits*/\n    }\n\n    /* too small of a word count */\n    dst = (nk_byte*)ptr;\n    if (size < 3 * nk_wsize) {\n        while (size--) *dst++ = (nk_byte)c0;\n        return;\n    }\n\n    /* align destination */\n    if ((t = NK_PTR_TO_UINT(dst) & nk_wmask) != 0) {\n        t = nk_wsize -t;\n        size -= t;\n        do {\n            *dst++ = (nk_byte)c0;\n        } while (--t != 0);\n    }\n\n    /* fill word */\n    t = size / nk_wsize;\n    do {\n        *(nk_word*)((void*)dst) = c;\n        dst += nk_wsize;\n    } while (--t != 0);\n\n    /* fill trailing bytes */\n    t = (size & nk_wmask);\n    if (t != 0) {\n        do {\n            *dst++ = (nk_byte)c0;\n        } while (--t != 0);\n    }\n\n    #undef nk_word\n    #undef nk_wsize\n    #undef nk_wmask\n}\n#endif\nNK_LIB void\nnk_zero(void *ptr, nk_size size)\n{\n    NK_ASSERT(ptr);\n    NK_MEMSET(ptr, 0, size);\n}\nNK_API int\nnk_strlen(const char *str)\n{\n    int siz = 0;\n    NK_ASSERT(str);\n    while (str && *str++ != '\\0') siz++;\n    return siz;\n}\nNK_API int\nnk_strtoi(const char *str, char **endptr)\n{\n    int neg = 1;\n    const char *p = str;\n    int value = 0;\n\n    NK_ASSERT(str);\n    if (!str) return 0;\n\n    /* skip whitespace */\n    while (*p == ' ') p++;\n    if (*p == '-') {\n        neg = -1;\n        p++;\n    }\n    while (*p && *p >= '0' && *p <= '9') {\n        value = value * 10 + (int) (*p - '0');\n        p++;\n    }\n    if (endptr)\n        *endptr = (char *)p;\n    return neg*value;\n}\n#ifdef NK_STRTOD_NEEDED\nNK_API double\nnk_strtod(const char *str, char **endptr)\n{\n    double m;\n    double neg = 1.0;\n    char *p = (char *)str;\n    double value = 0;\n    double number = 0;\n\n    NK_ASSERT(str);\n    if (!str) return 0;\n\n    /* skip whitespace */\n    while (*p == ' ') p++;\n    if (*p == '-') {\n        neg = -1.0;\n        p++;\n    }\n\n    while (*p && *p != '.' && *p != 'e') {\n        value = value * 10.0 + (double) (*p - '0');\n        p++;\n    }\n\n    if (*p == '.') {\n        p++;\n        for(m = 0.1; *p && *p != 'e'; p++ ) {\n            value = value + (double) (*p - '0') * m;\n            m *= 0.1;\n        }\n    }\n    if (*p == 'e') {\n        int i, pow, div;\n        p++;\n        if (*p == '-') {\n            div = nk_true;\n            p++;\n        } else if (*p == '+') {\n            div = nk_false;\n            p++;\n        } else div = nk_false;\n\n        for (pow = 0; *p; p++)\n            pow = pow * 10 + (int) (*p - '0');\n\n        for (m = 1.0, i = 0; i < pow; i++)\n            m *= 10.0;\n\n        if (div)\n            value /= m;\n        else value *= m;\n    }\n    number = value * neg;\n    if (endptr)\n        *endptr = (char *)p;\n    return number;\n}\n#endif\nNK_API float\nnk_strtof(const char *str, char **endptr)\n{\n    float float_value;\n    double double_value;\n    double_value = NK_STRTOD(str, endptr);\n    float_value = (float)double_value;\n    return float_value;\n}\nNK_API int\nnk_stricmp(const char *s1, const char *s2)\n{\n    nk_int c1,c2,d;\n    do {\n        c1 = *s1++;\n        c2 = *s2++;\n        d = c1 - c2;\n        while (d) {\n            if (c1 <= 'Z' && c1 >= 'A') {\n                d += ('a' - 'A');\n                if (!d) break;\n            }\n            if (c2 <= 'Z' && c2 >= 'A') {\n                d -= ('a' - 'A');\n                if (!d) break;\n            }\n            return ((d >= 0) << 1) - 1;\n        }\n    } while (c1);\n    return 0;\n}\nNK_API int\nnk_stricmpn(const char *s1, const char *s2, int n)\n{\n    int c1,c2,d;\n    NK_ASSERT(n >= 0);\n    do {\n        c1 = *s1++;\n        c2 = *s2++;\n        if (!n--) return 0;\n\n        d = c1 - c2;\n        while (d) {\n            if (c1 <= 'Z' && c1 >= 'A') {\n                d += ('a' - 'A');\n                if (!d) break;\n            }\n            if (c2 <= 'Z' && c2 >= 'A') {\n                d -= ('a' - 'A');\n                if (!d) break;\n            }\n            return ((d >= 0) << 1) - 1;\n        }\n    } while (c1);\n    return 0;\n}\nNK_INTERN int\nnk_str_match_here(const char *regexp, const char *text)\n{\n    if (regexp[0] == '\\0')\n        return 1;\n    if (regexp[1] == '*')\n        return nk_str_match_star(regexp[0], regexp+2, text);\n    if (regexp[0] == '$' && regexp[1] == '\\0')\n        return *text == '\\0';\n    if (*text!='\\0' && (regexp[0]=='.' || regexp[0]==*text))\n        return nk_str_match_here(regexp+1, text+1);\n    return 0;\n}\nNK_INTERN int\nnk_str_match_star(int c, const char *regexp, const char *text)\n{\n    do {/* a '* matches zero or more instances */\n        if (nk_str_match_here(regexp, text))\n            return 1;\n    } while (*text != '\\0' && (*text++ == c || c == '.'));\n    return 0;\n}\nNK_API int\nnk_strfilter(const char *text, const char *regexp)\n{\n    /*\n    c    matches any literal character c\n    .    matches any single character\n    ^    matches the beginning of the input string\n    $    matches the end of the input string\n    *    matches zero or more occurrences of the previous character*/\n    if (regexp[0] == '^')\n        return nk_str_match_here(regexp+1, text);\n    do {    /* must look even if string is empty */\n        if (nk_str_match_here(regexp, text))\n            return 1;\n    } while (*text++ != '\\0');\n    return 0;\n}\nNK_API int\nnk_strmatch_fuzzy_text(const char *str, int str_len,\n    const char *pattern, int *out_score)\n{\n    /* Returns true if each character in pattern is found sequentially within str\n     * if found then out_score is also set. Score value has no intrinsic meaning.\n     * Range varies with pattern. Can only compare scores with same search pattern. */\n\n    /* bonus for adjacent matches */\n    #define NK_ADJACENCY_BONUS 5\n    /* bonus if match occurs after a separator */\n    #define NK_SEPARATOR_BONUS 10\n    /* bonus if match is uppercase and prev is lower */\n    #define NK_CAMEL_BONUS 10\n    /* penalty applied for every letter in str before the first match */\n    #define NK_LEADING_LETTER_PENALTY (-3)\n    /* maximum penalty for leading letters */\n    #define NK_MAX_LEADING_LETTER_PENALTY (-9)\n    /* penalty for every letter that doesn't matter */\n    #define NK_UNMATCHED_LETTER_PENALTY (-1)\n\n    /* loop variables */\n    int score = 0;\n    char const * pattern_iter = pattern;\n    int str_iter = 0;\n    int prev_matched = nk_false;\n    int prev_lower = nk_false;\n    /* true so if first letter match gets separator bonus*/\n    int prev_separator = nk_true;\n\n    /* use \"best\" matched letter if multiple string letters match the pattern */\n    char const * best_letter = 0;\n    int best_letter_score = 0;\n\n    /* loop over strings */\n    NK_ASSERT(str);\n    NK_ASSERT(pattern);\n    if (!str || !str_len || !pattern) return 0;\n    while (str_iter < str_len)\n    {\n        const char pattern_letter = *pattern_iter;\n        const char str_letter = str[str_iter];\n\n        int next_match = *pattern_iter != '\\0' &&\n            nk_to_lower(pattern_letter) == nk_to_lower(str_letter);\n        int rematch = best_letter && nk_to_upper(*best_letter) == nk_to_upper(str_letter);\n\n        int advanced = next_match && best_letter;\n        int pattern_repeat = best_letter && *pattern_iter != '\\0';\n        pattern_repeat = pattern_repeat &&\n            nk_to_lower(*best_letter) == nk_to_lower(pattern_letter);\n\n        if (advanced || pattern_repeat) {\n            score += best_letter_score;\n            best_letter = 0;\n            best_letter_score = 0;\n        }\n\n        if (next_match || rematch)\n        {\n            int new_score = 0;\n            /* Apply penalty for each letter before the first pattern match */\n            if (pattern_iter == pattern) {\n                int count = (int)(&str[str_iter] - str);\n                int penalty = NK_LEADING_LETTER_PENALTY * count;\n                if (penalty < NK_MAX_LEADING_LETTER_PENALTY)\n                    penalty = NK_MAX_LEADING_LETTER_PENALTY;\n\n                score += penalty;\n            }\n\n            /* apply bonus for consecutive bonuses */\n            if (prev_matched)\n                new_score += NK_ADJACENCY_BONUS;\n\n            /* apply bonus for matches after a separator */\n            if (prev_separator)\n                new_score += NK_SEPARATOR_BONUS;\n\n            /* apply bonus across camel case boundaries */\n            if (prev_lower && nk_is_upper(str_letter))\n                new_score += NK_CAMEL_BONUS;\n\n            /* update pattern iter IFF the next pattern letter was matched */\n            if (next_match)\n                ++pattern_iter;\n\n            /* update best letter in str which may be for a \"next\" letter or a rematch */\n            if (new_score >= best_letter_score) {\n                /* apply penalty for now skipped letter */\n                if (best_letter != 0)\n                    score += NK_UNMATCHED_LETTER_PENALTY;\n\n                best_letter = &str[str_iter];\n                best_letter_score = new_score;\n            }\n            prev_matched = nk_true;\n        } else {\n            score += NK_UNMATCHED_LETTER_PENALTY;\n            prev_matched = nk_false;\n        }\n\n        /* separators should be more easily defined */\n        prev_lower = nk_is_lower(str_letter) != 0;\n        prev_separator = str_letter == '_' || str_letter == ' ';\n\n        ++str_iter;\n    }\n\n    /* apply score for last match */\n    if (best_letter)\n        score += best_letter_score;\n\n    /* did not match full pattern */\n    if (*pattern_iter != '\\0')\n        return nk_false;\n\n    if (out_score)\n        *out_score = score;\n    return nk_true;\n}\nNK_API int\nnk_strmatch_fuzzy_string(char const *str, char const *pattern, int *out_score)\n{\n    return nk_strmatch_fuzzy_text(str, nk_strlen(str), pattern, out_score);\n}\nNK_LIB int\nnk_string_float_limit(char *string, int prec)\n{\n    int dot = 0;\n    char *c = string;\n    while (*c) {\n        if (*c == '.') {\n            dot = 1;\n            c++;\n            continue;\n        }\n        if (dot == (prec+1)) {\n            *c = 0;\n            break;\n        }\n        if (dot > 0) dot++;\n        c++;\n    }\n    return (int)(c - string);\n}\nNK_INTERN void\nnk_strrev_ascii(char *s)\n{\n    int len = nk_strlen(s);\n    int end = len / 2;\n    int i = 0;\n    char t;\n    for (; i < end; ++i) {\n        t = s[i];\n        s[i] = s[len - 1 - i];\n        s[len -1 - i] = t;\n    }\n}\nNK_LIB char*\nnk_itoa(char *s, long n)\n{\n    long i = 0;\n    if (n == 0) {\n        s[i++] = '0';\n        s[i] = 0;\n        return s;\n    }\n    if (n < 0) {\n        s[i++] = '-';\n        n = -n;\n    }\n    while (n > 0) {\n        s[i++] = (char)('0' + (n % 10));\n        n /= 10;\n    }\n    s[i] = 0;\n    if (s[0] == '-')\n        ++s;\n\n    nk_strrev_ascii(s);\n    return s;\n}\n#ifdef NK_DTOA_NEEDED\nNK_LIB char*\nnk_dtoa(char *s, double n)\n{\n    int useExp = 0;\n    int digit = 0, m = 0, m1 = 0;\n    char *c = s;\n    int neg = 0;\n\n    NK_ASSERT(s);\n    if (!s) return 0;\n\n    if (n == 0.0) {\n        s[0] = '0'; s[1] = '\\0';\n        return s;\n    }\n\n    neg = (n < 0);\n    if (neg) n = -n;\n\n    /* calculate magnitude */\n    m = nk_log10(n);\n    useExp = (m >= 14 || (neg && m >= 9) || m <= -9);\n    if (neg) *(c++) = '-';\n\n    /* set up for scientific notation */\n    if (useExp) {\n        if (m < 0)\n           m -= 1;\n        n = n / (double)nk_pow(10.0, m);\n        m1 = m;\n        m = 0;\n    }\n    if (m < 1.0) {\n        m = 0;\n    }\n\n    /* convert the number */\n    while (n > NK_FLOAT_PRECISION || m >= 0) {\n        double weight = nk_pow(10.0, m);\n        if (weight > 0) {\n            double t = (double)n / weight;\n            digit = nk_ifloord(t);\n            n -= ((double)digit * weight);\n            *(c++) = (char)('0' + (char)digit);\n        }\n        if (m == 0 && n > 0)\n            *(c++) = '.';\n        m--;\n    }\n\n    if (useExp) {\n        /* convert the exponent */\n        int i, j;\n        *(c++) = 'e';\n        if (m1 > 0) {\n            *(c++) = '+';\n        } else {\n            *(c++) = '-';\n            m1 = -m1;\n        }\n        m = 0;\n        while (m1 > 0) {\n            *(c++) = (char)('0' + (char)(m1 % 10));\n            m1 /= 10;\n            m++;\n        }\n        c -= m;\n        for (i = 0, j = m-1; i<j; i++, j--) {\n            /* swap without temporary */\n            c[i] ^= c[j];\n            c[j] ^= c[i];\n            c[i] ^= c[j];\n        }\n        c += m;\n    }\n    *(c) = '\\0';\n    return s;\n}\n#endif\n#ifdef NK_INCLUDE_STANDARD_VARARGS\n#ifndef NK_INCLUDE_STANDARD_IO\nNK_INTERN int\nnk_vsnprintf(char *buf, int buf_size, const char *fmt, va_list args)\n{\n    enum nk_arg_type {\n        NK_ARG_TYPE_CHAR,\n        NK_ARG_TYPE_SHORT,\n        NK_ARG_TYPE_DEFAULT,\n        NK_ARG_TYPE_LONG\n    };\n    enum nk_arg_flags {\n        NK_ARG_FLAG_LEFT = 0x01,\n        NK_ARG_FLAG_PLUS = 0x02,\n        NK_ARG_FLAG_SPACE = 0x04,\n        NK_ARG_FLAG_NUM = 0x10,\n        NK_ARG_FLAG_ZERO = 0x20\n    };\n\n    char number_buffer[NK_MAX_NUMBER_BUFFER];\n    enum nk_arg_type arg_type = NK_ARG_TYPE_DEFAULT;\n    int precision = NK_DEFAULT;\n    int width = NK_DEFAULT;\n    nk_flags flag = 0;\n\n    int len = 0;\n    int result = -1;\n    const char *iter = fmt;\n\n    NK_ASSERT(buf);\n    NK_ASSERT(buf_size);\n    if (!buf || !buf_size || !fmt) return 0;\n    for (iter = fmt; *iter && len < buf_size; iter++) {\n        /* copy all non-format characters */\n        while (*iter && (*iter != '%') && (len < buf_size))\n            buf[len++] = *iter++;\n        if (!(*iter) || len >= buf_size) break;\n        iter++;\n\n        /* flag arguments */\n        while (*iter) {\n            if (*iter == '-') flag |= NK_ARG_FLAG_LEFT;\n            else if (*iter == '+') flag |= NK_ARG_FLAG_PLUS;\n            else if (*iter == ' ') flag |= NK_ARG_FLAG_SPACE;\n            else if (*iter == '#') flag |= NK_ARG_FLAG_NUM;\n            else if (*iter == '0') flag |= NK_ARG_FLAG_ZERO;\n            else break;\n            iter++;\n        }\n\n        /* width argument */\n        width = NK_DEFAULT;\n        if (*iter >= '1' && *iter <= '9') {\n            char *end;\n            width = nk_strtoi(iter, &end);\n            if (end == iter)\n                width = -1;\n            else iter = end;\n        } else if (*iter == '*') {\n            width = va_arg(args, int);\n            iter++;\n        }\n\n        /* precision argument */\n        precision = NK_DEFAULT;\n        if (*iter == '.') {\n            iter++;\n            if (*iter == '*') {\n                precision = va_arg(args, int);\n                iter++;\n            } else {\n                char *end;\n                precision = nk_strtoi(iter, &end);\n                if (end == iter)\n                    precision = -1;\n                else iter = end;\n            }\n        }\n\n        /* length modifier */\n        if (*iter == 'h') {\n            if (*(iter+1) == 'h') {\n                arg_type = NK_ARG_TYPE_CHAR;\n                iter++;\n            } else arg_type = NK_ARG_TYPE_SHORT;\n            iter++;\n        } else if (*iter == 'l') {\n            arg_type = NK_ARG_TYPE_LONG;\n            iter++;\n        } else arg_type = NK_ARG_TYPE_DEFAULT;\n\n        /* specifier */\n        if (*iter == '%') {\n            NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);\n            NK_ASSERT(precision == NK_DEFAULT);\n            NK_ASSERT(width == NK_DEFAULT);\n            if (len < buf_size)\n                buf[len++] = '%';\n        } else if (*iter == 's') {\n            /* string  */\n            const char *str = va_arg(args, const char*);\n            NK_ASSERT(str != buf && \"buffer and argument are not allowed to overlap!\");\n            NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);\n            NK_ASSERT(precision == NK_DEFAULT);\n            NK_ASSERT(width == NK_DEFAULT);\n            if (str == buf) return -1;\n            while (str && *str && len < buf_size)\n                buf[len++] = *str++;\n        } else if (*iter == 'n') {\n            /* current length callback */\n            signed int *n = va_arg(args, int*);\n            NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);\n            NK_ASSERT(precision == NK_DEFAULT);\n            NK_ASSERT(width == NK_DEFAULT);\n            if (n) *n = len;\n        } else if (*iter == 'c' || *iter == 'i' || *iter == 'd') {\n            /* signed integer */\n            long value = 0;\n            const char *num_iter;\n            int num_len, num_print, padding;\n            int cur_precision = NK_MAX(precision, 1);\n            int cur_width = NK_MAX(width, 0);\n\n            /* retrieve correct value type */\n            if (arg_type == NK_ARG_TYPE_CHAR)\n                value = (signed char)va_arg(args, int);\n            else if (arg_type == NK_ARG_TYPE_SHORT)\n                value = (signed short)va_arg(args, int);\n            else if (arg_type == NK_ARG_TYPE_LONG)\n                value = va_arg(args, signed long);\n            else if (*iter == 'c')\n                value = (unsigned char)va_arg(args, int);\n            else value = va_arg(args, signed int);\n\n            /* convert number to string */\n            nk_itoa(number_buffer, value);\n            num_len = nk_strlen(number_buffer);\n            padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0);\n            if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE))\n                padding = NK_MAX(padding-1, 0);\n\n            /* fill left padding up to a total of `width` characters */\n            if (!(flag & NK_ARG_FLAG_LEFT)) {\n                while (padding-- > 0 && (len < buf_size)) {\n                    if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))\n                        buf[len++] = '0';\n                    else buf[len++] = ' ';\n                }\n            }\n\n            /* copy string value representation into buffer */\n            if ((flag & NK_ARG_FLAG_PLUS) && value >= 0 && len < buf_size)\n                buf[len++] = '+';\n            else if ((flag & NK_ARG_FLAG_SPACE) && value >= 0 && len < buf_size)\n                buf[len++] = ' ';\n\n            /* fill up to precision number of digits with '0' */\n            num_print = NK_MAX(cur_precision, num_len);\n            while (precision && (num_print > num_len) && (len < buf_size)) {\n                buf[len++] = '0';\n                num_print--;\n            }\n\n            /* copy string value representation into buffer */\n            num_iter = number_buffer;\n            while (precision && *num_iter && len < buf_size)\n                buf[len++] = *num_iter++;\n\n            /* fill right padding up to width characters */\n            if (flag & NK_ARG_FLAG_LEFT) {\n                while ((padding-- > 0) && (len < buf_size))\n                    buf[len++] = ' ';\n            }\n        } else if (*iter == 'o' || *iter == 'x' || *iter == 'X' || *iter == 'u') {\n            /* unsigned integer */\n            unsigned long value = 0;\n            int num_len = 0, num_print, padding = 0;\n            int cur_precision = NK_MAX(precision, 1);\n            int cur_width = NK_MAX(width, 0);\n            unsigned int base = (*iter == 'o') ? 8: (*iter == 'u')? 10: 16;\n\n            /* print oct/hex/dec value */\n            const char *upper_output_format = \"0123456789ABCDEF\";\n            const char *lower_output_format = \"0123456789abcdef\";\n            const char *output_format = (*iter == 'x') ?\n                lower_output_format: upper_output_format;\n\n            /* retrieve correct value type */\n            if (arg_type == NK_ARG_TYPE_CHAR)\n                value = (unsigned char)va_arg(args, int);\n            else if (arg_type == NK_ARG_TYPE_SHORT)\n                value = (unsigned short)va_arg(args, int);\n            else if (arg_type == NK_ARG_TYPE_LONG)\n                value = va_arg(args, unsigned long);\n            else value = va_arg(args, unsigned int);\n\n            do {\n                /* convert decimal number into hex/oct number */\n                int digit = output_format[value % base];\n                if (num_len < NK_MAX_NUMBER_BUFFER)\n                    number_buffer[num_len++] = (char)digit;\n                value /= base;\n            } while (value > 0);\n\n            num_print = NK_MAX(cur_precision, num_len);\n            padding = NK_MAX(cur_width - NK_MAX(cur_precision, num_len), 0);\n            if (flag & NK_ARG_FLAG_NUM)\n                padding = NK_MAX(padding-1, 0);\n\n            /* fill left padding up to a total of `width` characters */\n            if (!(flag & NK_ARG_FLAG_LEFT)) {\n                while ((padding-- > 0) && (len < buf_size)) {\n                    if ((flag & NK_ARG_FLAG_ZERO) && (precision == NK_DEFAULT))\n                        buf[len++] = '0';\n                    else buf[len++] = ' ';\n                }\n            }\n\n            /* fill up to precision number of digits */\n            if (num_print && (flag & NK_ARG_FLAG_NUM)) {\n                if ((*iter == 'o') && (len < buf_size)) {\n                    buf[len++] = '0';\n                } else if ((*iter == 'x') && ((len+1) < buf_size)) {\n                    buf[len++] = '0';\n                    buf[len++] = 'x';\n                } else if ((*iter == 'X') && ((len+1) < buf_size)) {\n                    buf[len++] = '0';\n                    buf[len++] = 'X';\n                }\n            }\n            while (precision && (num_print > num_len) && (len < buf_size)) {\n                buf[len++] = '0';\n                num_print--;\n            }\n\n            /* reverse number direction */\n            while (num_len > 0) {\n                if (precision && (len < buf_size))\n                    buf[len++] = number_buffer[num_len-1];\n                num_len--;\n            }\n\n            /* fill right padding up to width characters */\n            if (flag & NK_ARG_FLAG_LEFT) {\n                while ((padding-- > 0) && (len < buf_size))\n                    buf[len++] = ' ';\n            }\n        } else if (*iter == 'f') {\n            /* floating point */\n            const char *num_iter;\n            int cur_precision = (precision < 0) ? 6: precision;\n            int prefix, cur_width = NK_MAX(width, 0);\n            double value = va_arg(args, double);\n            int num_len = 0, frac_len = 0, dot = 0;\n            int padding = 0;\n\n            NK_ASSERT(arg_type == NK_ARG_TYPE_DEFAULT);\n            NK_DTOA(number_buffer, value);\n            num_len = nk_strlen(number_buffer);\n\n            /* calculate padding */\n            num_iter = number_buffer;\n            while (*num_iter && *num_iter != '.')\n                num_iter++;\n\n            prefix = (*num_iter == '.')?(int)(num_iter - number_buffer)+1:0;\n            padding = NK_MAX(cur_width - (prefix + NK_MIN(cur_precision, num_len - prefix)) , 0);\n            if ((flag & NK_ARG_FLAG_PLUS) || (flag & NK_ARG_FLAG_SPACE))\n                padding = NK_MAX(padding-1, 0);\n\n            /* fill left padding up to a total of `width` characters */\n            if (!(flag & NK_ARG_FLAG_LEFT)) {\n                while (padding-- > 0 && (len < buf_size)) {\n                    if (flag & NK_ARG_FLAG_ZERO)\n                        buf[len++] = '0';\n                    else buf[len++] = ' ';\n                }\n            }\n\n            /* copy string value representation into buffer */\n            num_iter = number_buffer;\n            if ((flag & NK_ARG_FLAG_PLUS) && (value >= 0) && (len < buf_size))\n                buf[len++] = '+';\n            else if ((flag & NK_ARG_FLAG_SPACE) && (value >= 0) && (len < buf_size))\n                buf[len++] = ' ';\n            while (*num_iter) {\n                if (dot) frac_len++;\n                if (len < buf_size)\n                    buf[len++] = *num_iter;\n                if (*num_iter == '.') dot = 1;\n                if (frac_len >= cur_precision) break;\n                num_iter++;\n            }\n\n            /* fill number up to precision */\n            while (frac_len < cur_precision) {\n                if (!dot && len < buf_size) {\n                    buf[len++] = '.';\n                    dot = 1;\n                }\n                if (len < buf_size)\n                    buf[len++] = '0';\n                frac_len++;\n            }\n\n            /* fill right padding up to width characters */\n            if (flag & NK_ARG_FLAG_LEFT) {\n                while ((padding-- > 0) && (len < buf_size))\n                    buf[len++] = ' ';\n            }\n        } else {\n            /* Specifier not supported: g,G,e,E,p,z */\n            NK_ASSERT(0 && \"specifier is not supported!\");\n            return result;\n        }\n    }\n    buf[(len >= buf_size)?(buf_size-1):len] = 0;\n    result = (len >= buf_size)?-1:len;\n    return result;\n}\n#endif\nNK_LIB int\nnk_strfmt(char *buf, int buf_size, const char *fmt, va_list args)\n{\n    int result = -1;\n    NK_ASSERT(buf);\n    NK_ASSERT(buf_size);\n    if (!buf || !buf_size || !fmt) return 0;\n#ifdef NK_INCLUDE_STANDARD_IO\n    result = NK_VSNPRINTF(buf, (nk_size)buf_size, fmt, args);\n    result = (result >= buf_size) ? -1: result;\n    buf[buf_size-1] = 0;\n#else\n    result = nk_vsnprintf(buf, buf_size, fmt, args);\n#endif\n    return result;\n}\n#endif\nNK_API nk_hash\nnk_murmur_hash(const void * key, int len, nk_hash seed)\n{\n    /* 32-Bit MurmurHash3: https://code.google.com/p/smhasher/wiki/MurmurHash3*/\n    #define NK_ROTL(x,r) ((x) << (r) | ((x) >> (32 - r)))\n\n    nk_uint h1 = seed;\n    nk_uint k1;\n    const nk_byte *data = (const nk_byte*)key;\n    const nk_byte *keyptr = data;\n    nk_byte *k1ptr;\n    const int bsize = sizeof(k1);\n    const int nblocks = len/4;\n\n    const nk_uint c1 = 0xcc9e2d51;\n    const nk_uint c2 = 0x1b873593;\n    const nk_byte *tail;\n    int i;\n\n    /* body */\n    if (!key) return 0;\n    for (i = 0; i < nblocks; ++i, keyptr += bsize) {\n        k1ptr = (nk_byte*)&k1;\n        k1ptr[0] = keyptr[0];\n        k1ptr[1] = keyptr[1];\n        k1ptr[2] = keyptr[2];\n        k1ptr[3] = keyptr[3];\n\n        k1 *= c1;\n        k1 = NK_ROTL(k1,15);\n        k1 *= c2;\n\n        h1 ^= k1;\n        h1 = NK_ROTL(h1,13);\n        h1 = h1*5+0xe6546b64;\n    }\n\n    /* tail */\n    tail = (const nk_byte*)(data + nblocks*4);\n    k1 = 0;\n    switch (len & 3) {\n        case 3: k1 ^= (nk_uint)(tail[2] << 16); /* fallthrough */\n        case 2: k1 ^= (nk_uint)(tail[1] << 8u); /* fallthrough */\n        case 1: k1 ^= tail[0];\n            k1 *= c1;\n            k1 = NK_ROTL(k1,15);\n            k1 *= c2;\n            h1 ^= k1;\n            break;\n        default: break;\n    }\n\n    /* finalization */\n    h1 ^= (nk_uint)len;\n    /* fmix32 */\n    h1 ^= h1 >> 16;\n    h1 *= 0x85ebca6b;\n    h1 ^= h1 >> 13;\n    h1 *= 0xc2b2ae35;\n    h1 ^= h1 >> 16;\n\n    #undef NK_ROTL\n    return h1;\n}\n#ifdef NK_INCLUDE_STANDARD_IO\nNK_LIB char*\nnk_file_load(const char* path, nk_size* siz, const struct nk_allocator *alloc)\n{\n    char *buf;\n    FILE *fd;\n    long ret;\n\n    NK_ASSERT(path);\n    NK_ASSERT(siz);\n    NK_ASSERT(alloc);\n    if (!path || !siz || !alloc)\n        return 0;\n\n    fd = fopen(path, \"rb\");\n    if (!fd) return 0;\n    fseek(fd, 0, SEEK_END);\n    ret = ftell(fd);\n    if (ret < 0) {\n        fclose(fd);\n        return 0;\n    }\n    *siz = (nk_size)ret;\n    fseek(fd, 0, SEEK_SET);\n    buf = (char*)alloc->alloc(alloc->userdata,0, *siz);\n    NK_ASSERT(buf);\n    if (!buf) {\n        fclose(fd);\n        return 0;\n    }\n    *siz = (nk_size)fread(buf, 1,*siz, fd);\n    fclose(fd);\n    return buf;\n}\n#endif\nNK_LIB int\nnk_text_clamp(const struct nk_user_font *font, const char *text,\n    int text_len, float space, int *glyphs, float *text_width,\n    nk_rune *sep_list, int sep_count)\n{\n    int i = 0;\n    int glyph_len = 0;\n    float last_width = 0;\n    nk_rune unicode = 0;\n    float width = 0;\n    int len = 0;\n    int g = 0;\n    float s;\n\n    int sep_len = 0;\n    int sep_g = 0;\n    float sep_width = 0;\n    sep_count = NK_MAX(sep_count,0);\n\n    glyph_len = nk_utf_decode(text, &unicode, text_len);\n    while (glyph_len && (width < space) && (len < text_len)) {\n        len += glyph_len;\n        s = font->width(font->userdata, font->height, text, len);\n        for (i = 0; i < sep_count; ++i) {\n            if (unicode != sep_list[i]) continue;\n            sep_width = last_width = width;\n            sep_g = g+1;\n            sep_len = len;\n            break;\n        }\n        if (i == sep_count){\n            last_width = sep_width = width;\n            sep_g = g+1;\n        }\n        width = s;\n        glyph_len = nk_utf_decode(&text[len], &unicode, text_len - len);\n        g++;\n    }\n    if (len >= text_len) {\n        *glyphs = g;\n        *text_width = last_width;\n        return len;\n    } else {\n        *glyphs = sep_g;\n        *text_width = sep_width;\n        return (!sep_len) ? len: sep_len;\n    }\n}\nNK_LIB struct nk_vec2\nnk_text_calculate_text_bounds(const struct nk_user_font *font,\n    const char *begin, int byte_len, float row_height, const char **remaining,\n    struct nk_vec2 *out_offset, int *glyphs, int op)\n{\n    float line_height = row_height;\n    struct nk_vec2 text_size = nk_vec2(0,0);\n    float line_width = 0.0f;\n\n    float glyph_width;\n    int glyph_len = 0;\n    nk_rune unicode = 0;\n    int text_len = 0;\n    if (!begin || byte_len <= 0 || !font)\n        return nk_vec2(0,row_height);\n\n    glyph_len = nk_utf_decode(begin, &unicode, byte_len);\n    if (!glyph_len) return text_size;\n    glyph_width = font->width(font->userdata, font->height, begin, glyph_len);\n\n    *glyphs = 0;\n    while ((text_len < byte_len) && glyph_len) {\n        if (unicode == '\\n') {\n            text_size.x = NK_MAX(text_size.x, line_width);\n            text_size.y += line_height;\n            line_width = 0;\n            *glyphs+=1;\n            if (op == NK_STOP_ON_NEW_LINE)\n                break;\n\n            text_len++;\n            glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);\n            continue;\n        }\n\n        if (unicode == '\\r') {\n            text_len++;\n            *glyphs+=1;\n            glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);\n            continue;\n        }\n\n        *glyphs = *glyphs + 1;\n        text_len += glyph_len;\n        line_width += (float)glyph_width;\n        glyph_len = nk_utf_decode(begin + text_len, &unicode, byte_len-text_len);\n        glyph_width = font->width(font->userdata, font->height, begin+text_len, glyph_len);\n        continue;\n    }\n\n    if (text_size.x < line_width)\n        text_size.x = line_width;\n    if (out_offset)\n        *out_offset = nk_vec2(line_width, text_size.y + line_height);\n    if (line_width > 0 || text_size.y == 0.0f)\n        text_size.y += line_height;\n    if (remaining)\n        *remaining = begin+text_len;\n    return text_size;\n}\n\n"
  },
  {
    "path": "src/nuklear_vertex.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              VERTEX\n *\n * ===============================================================*/\n#ifdef NK_INCLUDE_VERTEX_BUFFER_OUTPUT\nNK_API void\nnk_draw_list_init(struct nk_draw_list *list)\n{\n    nk_size i = 0;\n    NK_ASSERT(list);\n    if (!list) return;\n    nk_zero(list, sizeof(*list));\n    for (i = 0; i < NK_LEN(list->circle_vtx); ++i) {\n        const float a = ((float)i / (float)NK_LEN(list->circle_vtx)) * 2 * NK_PI;\n        list->circle_vtx[i].x = (float)NK_COS(a);\n        list->circle_vtx[i].y = (float)NK_SIN(a);\n    }\n}\nNK_API void\nnk_draw_list_setup(struct nk_draw_list *canvas, const struct nk_convert_config *config,\n    struct nk_buffer *cmds, struct nk_buffer *vertices, struct nk_buffer *elements,\n    enum nk_anti_aliasing line_aa, enum nk_anti_aliasing shape_aa)\n{\n    NK_ASSERT(canvas);\n    NK_ASSERT(config);\n    NK_ASSERT(cmds);\n    NK_ASSERT(vertices);\n    NK_ASSERT(elements);\n    if (!canvas || !config || !cmds || !vertices || !elements)\n        return;\n\n    canvas->buffer = cmds;\n    canvas->config = *config;\n    canvas->elements = elements;\n    canvas->vertices = vertices;\n    canvas->line_AA = line_aa;\n    canvas->shape_AA = shape_aa;\n    canvas->clip_rect = nk_null_rect;\n\n    canvas->cmd_offset = 0;\n    canvas->element_count = 0;\n    canvas->vertex_count = 0;\n    canvas->cmd_offset = 0;\n    canvas->cmd_count = 0;\n    canvas->path_count = 0;\n}\nNK_API const struct nk_draw_command*\nnk__draw_list_begin(const struct nk_draw_list *canvas, const struct nk_buffer *buffer)\n{\n    nk_byte *memory;\n    nk_size offset;\n    const struct nk_draw_command *cmd;\n\n    NK_ASSERT(buffer);\n    if (!buffer || !buffer->size || !canvas->cmd_count)\n        return 0;\n\n    memory = (nk_byte*)buffer->memory.ptr;\n    offset = buffer->memory.size - canvas->cmd_offset;\n    cmd = nk_ptr_add(const struct nk_draw_command, memory, offset);\n    return cmd;\n}\nNK_API const struct nk_draw_command*\nnk__draw_list_end(const struct nk_draw_list *canvas, const struct nk_buffer *buffer)\n{\n    nk_size size;\n    nk_size offset;\n    nk_byte *memory;\n    const struct nk_draw_command *end;\n\n    NK_ASSERT(buffer);\n    NK_ASSERT(canvas);\n    if (!buffer || !canvas)\n        return 0;\n\n    memory = (nk_byte*)buffer->memory.ptr;\n    size = buffer->memory.size;\n    offset = size - canvas->cmd_offset;\n    end = nk_ptr_add(const struct nk_draw_command, memory, offset);\n    end -= (canvas->cmd_count-1);\n    return end;\n}\nNK_API const struct nk_draw_command*\nnk__draw_list_next(const struct nk_draw_command *cmd,\n    const struct nk_buffer *buffer, const struct nk_draw_list *canvas)\n{\n    const struct nk_draw_command *end;\n    NK_ASSERT(buffer);\n    NK_ASSERT(canvas);\n    if (!cmd || !buffer || !canvas)\n        return 0;\n\n    end = nk__draw_list_end(canvas, buffer);\n    if (cmd <= end) return 0;\n    return (cmd-1);\n}\nNK_INTERN struct nk_vec2*\nnk_draw_list_alloc_path(struct nk_draw_list *list, int count)\n{\n    struct nk_vec2 *points;\n    NK_STORAGE const nk_size point_align = NK_ALIGNOF(struct nk_vec2);\n    NK_STORAGE const nk_size point_size = sizeof(struct nk_vec2);\n    points = (struct nk_vec2*)\n        nk_buffer_alloc(list->buffer, NK_BUFFER_FRONT,\n                        point_size * (nk_size)count, point_align);\n\n    if (!points) return 0;\n    if (!list->path_offset) {\n        void *memory = nk_buffer_memory(list->buffer);\n        list->path_offset = (unsigned int)((nk_byte*)points - (nk_byte*)memory);\n    }\n    list->path_count += (unsigned int)count;\n    return points;\n}\nNK_INTERN struct nk_vec2\nnk_draw_list_path_last(struct nk_draw_list *list)\n{\n    void *memory;\n    struct nk_vec2 *point;\n    NK_ASSERT(list->path_count);\n    memory = nk_buffer_memory(list->buffer);\n    point = nk_ptr_add(struct nk_vec2, memory, list->path_offset);\n    point += (list->path_count-1);\n    return *point;\n}\nNK_INTERN struct nk_draw_command*\nnk_draw_list_push_command(struct nk_draw_list *list, struct nk_rect clip,\n    nk_handle texture)\n{\n    NK_STORAGE const nk_size cmd_align = NK_ALIGNOF(struct nk_draw_command);\n    NK_STORAGE const nk_size cmd_size = sizeof(struct nk_draw_command);\n    struct nk_draw_command *cmd;\n\n    NK_ASSERT(list);\n    cmd = (struct nk_draw_command*)\n        nk_buffer_alloc(list->buffer, NK_BUFFER_BACK, cmd_size, cmd_align);\n\n    if (!cmd) return 0;\n    if (!list->cmd_count) {\n        nk_byte *memory = (nk_byte*)nk_buffer_memory(list->buffer);\n        nk_size total = nk_buffer_total(list->buffer);\n        memory = nk_ptr_add(nk_byte, memory, total);\n        list->cmd_offset = (nk_size)(memory - (nk_byte*)cmd);\n    }\n\n    cmd->elem_count = 0;\n    cmd->clip_rect = clip;\n    cmd->texture = texture;\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    cmd->userdata = list->userdata;\n#endif\n\n    list->cmd_count++;\n    list->clip_rect = clip;\n    return cmd;\n}\nNK_INTERN struct nk_draw_command*\nnk_draw_list_command_last(struct nk_draw_list *list)\n{\n    void *memory;\n    nk_size size;\n    struct nk_draw_command *cmd;\n    NK_ASSERT(list->cmd_count);\n\n    memory = nk_buffer_memory(list->buffer);\n    size = nk_buffer_total(list->buffer);\n    cmd = nk_ptr_add(struct nk_draw_command, memory, size - list->cmd_offset);\n    return (cmd - (list->cmd_count-1));\n}\nNK_INTERN void\nnk_draw_list_add_clip(struct nk_draw_list *list, struct nk_rect rect)\n{\n    NK_ASSERT(list);\n    if (!list) return;\n    if (!list->cmd_count) {\n        nk_draw_list_push_command(list, rect, list->config.tex_null.texture);\n    } else {\n        struct nk_draw_command *prev = nk_draw_list_command_last(list);\n        if (prev->elem_count == 0)\n            prev->clip_rect = rect;\n        nk_draw_list_push_command(list, rect, prev->texture);\n    }\n}\nNK_INTERN void\nnk_draw_list_push_image(struct nk_draw_list *list, nk_handle texture)\n{\n    NK_ASSERT(list);\n    if (!list) return;\n    if (!list->cmd_count) {\n        nk_draw_list_push_command(list, nk_null_rect, texture);\n    } else {\n        struct nk_draw_command *prev = nk_draw_list_command_last(list);\n        if (prev->elem_count == 0) {\n            prev->texture = texture;\n            #ifdef NK_INCLUDE_COMMAND_USERDATA\n            prev->userdata = list->userdata;\n            #endif\n        } else if (prev->texture.id != texture.id\n                #ifdef NK_INCLUDE_COMMAND_USERDATA\n                || prev->userdata.id != list->userdata.id\n                #endif\n                ) {\n            nk_draw_list_push_command(list, prev->clip_rect, texture);\n        }\n    }\n}\n#ifdef NK_INCLUDE_COMMAND_USERDATA\nNK_API void\nnk_draw_list_push_userdata(struct nk_draw_list *list, nk_handle userdata)\n{\n    list->userdata = userdata;\n}\n#endif\nNK_INTERN void*\nnk_draw_list_alloc_vertices(struct nk_draw_list *list, nk_size count)\n{\n    void *vtx;\n    NK_ASSERT(list);\n    if (!list) return 0;\n    vtx = nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT,\n        list->config.vertex_size*count, list->config.vertex_alignment);\n    if (!vtx) return 0;\n    list->vertex_count += (unsigned int)count;\n\n    /* This assert triggers because your are drawing a lot of stuff and nuklear\n     * defined `nk_draw_index` as `nk_ushort` to safe space be default.\n     *\n     * So you reached the maximum number of indices or rather vertexes.\n     * To solve this issue please change typedef `nk_draw_index` to `nk_uint`\n     * and don't forget to specify the new element size in your drawing\n     * backend (OpenGL, DirectX, ...). For example in OpenGL for `glDrawElements`\n     * instead of specifying `GL_UNSIGNED_SHORT` you have to define `GL_UNSIGNED_INT`.\n     * Sorry for the inconvenience. */\n    if(sizeof(nk_draw_index)==2) NK_ASSERT((list->vertex_count < NK_USHORT_MAX &&\n        \"To many vertices for 16-bit vertex indices. Please read comment above on how to solve this problem\"));\n    return vtx;\n}\nNK_INTERN nk_draw_index*\nnk_draw_list_alloc_elements(struct nk_draw_list *list, nk_size count)\n{\n    nk_draw_index *ids;\n    struct nk_draw_command *cmd;\n    NK_STORAGE const nk_size elem_align = NK_ALIGNOF(nk_draw_index);\n    NK_STORAGE const nk_size elem_size = sizeof(nk_draw_index);\n    NK_ASSERT(list);\n    if (!list) return 0;\n\n    ids = (nk_draw_index*)\n        nk_buffer_alloc(list->elements, NK_BUFFER_FRONT, elem_size*count, elem_align);\n    if (!ids) return 0;\n    cmd = nk_draw_list_command_last(list);\n    list->element_count += (unsigned int)count;\n    cmd->elem_count += (unsigned int)count;\n    return ids;\n}\nNK_INTERN int\nnk_draw_vertex_layout_element_is_end_of_layout(\n    const struct nk_draw_vertex_layout_element *element)\n{\n    return (element->attribute == NK_VERTEX_ATTRIBUTE_COUNT ||\n            element->format == NK_FORMAT_COUNT);\n}\nNK_INTERN void\nnk_draw_vertex_color(void *attr, const float *vals,\n    enum nk_draw_vertex_layout_format format)\n{\n    /* if this triggers you tried to provide a value format for a color */\n    float val[4];\n    NK_ASSERT(format >= NK_FORMAT_COLOR_BEGIN);\n    NK_ASSERT(format <= NK_FORMAT_COLOR_END);\n    if (format < NK_FORMAT_COLOR_BEGIN || format > NK_FORMAT_COLOR_END) return;\n\n    val[0] = NK_SATURATE(vals[0]);\n    val[1] = NK_SATURATE(vals[1]);\n    val[2] = NK_SATURATE(vals[2]);\n    val[3] = NK_SATURATE(vals[3]);\n\n    switch (format) {\n    default: NK_ASSERT(0 && \"Invalid vertex layout color format\"); break;\n    case NK_FORMAT_R8G8B8A8:\n    case NK_FORMAT_R8G8B8: {\n        struct nk_color col = nk_rgba_fv(val);\n        NK_MEMCPY(attr, &col.r, sizeof(col));\n    } break;\n    case NK_FORMAT_B8G8R8A8: {\n        struct nk_color col = nk_rgba_fv(val);\n        struct nk_color bgra = nk_rgba(col.b, col.g, col.r, col.a);\n        NK_MEMCPY(attr, &bgra, sizeof(bgra));\n    } break;\n    case NK_FORMAT_R16G15B16: {\n        nk_ushort col[3];\n        col[0] = (nk_ushort)(val[0]*(float)NK_USHORT_MAX);\n        col[1] = (nk_ushort)(val[1]*(float)NK_USHORT_MAX);\n        col[2] = (nk_ushort)(val[2]*(float)NK_USHORT_MAX);\n        NK_MEMCPY(attr, col, sizeof(col));\n    } break;\n    case NK_FORMAT_R16G15B16A16: {\n        nk_ushort col[4];\n        col[0] = (nk_ushort)(val[0]*(float)NK_USHORT_MAX);\n        col[1] = (nk_ushort)(val[1]*(float)NK_USHORT_MAX);\n        col[2] = (nk_ushort)(val[2]*(float)NK_USHORT_MAX);\n        col[3] = (nk_ushort)(val[3]*(float)NK_USHORT_MAX);\n        NK_MEMCPY(attr, col, sizeof(col));\n    } break;\n    case NK_FORMAT_R32G32B32: {\n        nk_uint col[3];\n        col[0] = (nk_uint)(val[0]*(float)NK_UINT_MAX);\n        col[1] = (nk_uint)(val[1]*(float)NK_UINT_MAX);\n        col[2] = (nk_uint)(val[2]*(float)NK_UINT_MAX);\n        NK_MEMCPY(attr, col, sizeof(col));\n    } break;\n    case NK_FORMAT_R32G32B32A32: {\n        nk_uint col[4];\n        col[0] = (nk_uint)(val[0]*(float)NK_UINT_MAX);\n        col[1] = (nk_uint)(val[1]*(float)NK_UINT_MAX);\n        col[2] = (nk_uint)(val[2]*(float)NK_UINT_MAX);\n        col[3] = (nk_uint)(val[3]*(float)NK_UINT_MAX);\n        NK_MEMCPY(attr, col, sizeof(col));\n    } break;\n    case NK_FORMAT_R32G32B32A32_FLOAT:\n        NK_MEMCPY(attr, val, sizeof(float)*4);\n        break;\n    case NK_FORMAT_R32G32B32A32_DOUBLE: {\n        double col[4];\n        col[0] = (double)val[0];\n        col[1] = (double)val[1];\n        col[2] = (double)val[2];\n        col[3] = (double)val[3];\n        NK_MEMCPY(attr, col, sizeof(col));\n    } break;\n    case NK_FORMAT_RGB32:\n    case NK_FORMAT_RGBA32: {\n        struct nk_color col = nk_rgba_fv(val);\n        nk_uint color = nk_color_u32(col);\n        NK_MEMCPY(attr, &color, sizeof(color));\n    } break; }\n}\nNK_INTERN void\nnk_draw_vertex_element(void *dst, const float *values, int value_count,\n    enum nk_draw_vertex_layout_format format)\n{\n    int value_index;\n    void *attribute = dst;\n    /* if this triggers you tried to provide a color format for a value */\n    NK_ASSERT(format < NK_FORMAT_COLOR_BEGIN);\n    if (format >= NK_FORMAT_COLOR_BEGIN && format <= NK_FORMAT_COLOR_END) return;\n    for (value_index = 0; value_index < value_count; ++value_index) {\n        switch (format) {\n        default: NK_ASSERT(0 && \"invalid vertex layout format\"); break;\n        case NK_FORMAT_SCHAR: {\n            char value = (char)NK_CLAMP((float)NK_SCHAR_MIN, values[value_index], (float)NK_SCHAR_MAX);\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(char));\n        } break;\n        case NK_FORMAT_SSHORT: {\n            nk_short value = (nk_short)NK_CLAMP((float)NK_SSHORT_MIN, values[value_index], (float)NK_SSHORT_MAX);\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(value));\n        } break;\n        case NK_FORMAT_SINT: {\n            nk_int value = (nk_int)NK_CLAMP((float)NK_SINT_MIN, values[value_index], (float)NK_SINT_MAX);\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(nk_int));\n        } break;\n        case NK_FORMAT_UCHAR: {\n            unsigned char value = (unsigned char)NK_CLAMP((float)NK_UCHAR_MIN, values[value_index], (float)NK_UCHAR_MAX);\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(unsigned char));\n        } break;\n        case NK_FORMAT_USHORT: {\n            nk_ushort value = (nk_ushort)NK_CLAMP((float)NK_USHORT_MIN, values[value_index], (float)NK_USHORT_MAX);\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(value));\n            } break;\n        case NK_FORMAT_UINT: {\n            nk_uint value = (nk_uint)NK_CLAMP((float)NK_UINT_MIN, values[value_index], (float)NK_UINT_MAX);\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(nk_uint));\n        } break;\n        case NK_FORMAT_FLOAT:\n            NK_MEMCPY(attribute, &values[value_index], sizeof(values[value_index]));\n            attribute = (void*)((char*)attribute + sizeof(float));\n            break;\n        case NK_FORMAT_DOUBLE: {\n            double value = (double)values[value_index];\n            NK_MEMCPY(attribute, &value, sizeof(value));\n            attribute = (void*)((char*)attribute + sizeof(double));\n            } break;\n        }\n    }\n}\nNK_INTERN void*\nnk_draw_vertex(void *dst, const struct nk_convert_config *config,\n    struct nk_vec2 pos, struct nk_vec2 uv, struct nk_colorf color)\n{\n    void *result = (void*)((char*)dst + config->vertex_size);\n    const struct nk_draw_vertex_layout_element *elem_iter = config->vertex_layout;\n    while (!nk_draw_vertex_layout_element_is_end_of_layout(elem_iter)) {\n        void *address = (void*)((char*)dst + elem_iter->offset);\n        switch (elem_iter->attribute) {\n        case NK_VERTEX_ATTRIBUTE_COUNT:\n        default: NK_ASSERT(0 && \"wrong element attribute\"); break;\n        case NK_VERTEX_POSITION: nk_draw_vertex_element(address, &pos.x, 2, elem_iter->format); break;\n        case NK_VERTEX_TEXCOORD: nk_draw_vertex_element(address, &uv.x, 2, elem_iter->format); break;\n        case NK_VERTEX_COLOR: nk_draw_vertex_color(address, &color.r, elem_iter->format); break;\n        }\n        elem_iter++;\n    }\n    return result;\n}\nNK_API void\nnk_draw_list_stroke_poly_line(struct nk_draw_list *list, const struct nk_vec2 *points,\n    const unsigned int points_count, struct nk_color color, enum nk_draw_list_stroke closed,\n    float thickness, enum nk_anti_aliasing aliasing)\n{\n    nk_size count;\n    int thick_line;\n    struct nk_colorf col;\n    struct nk_colorf col_trans;\n    NK_ASSERT(list);\n    if (!list || points_count < 2) return;\n\n    color.a = (nk_byte)((float)color.a * list->config.global_alpha);\n    count = points_count;\n    if (!closed) count = points_count-1;\n    thick_line = thickness > 1.0f;\n\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    nk_draw_list_push_userdata(list, list->userdata);\n#endif\n\n    color.a = (nk_byte)((float)color.a * list->config.global_alpha);\n    nk_color_fv(&col.r, color);\n    col_trans = col;\n    col_trans.a = 0;\n\n    if (aliasing == NK_ANTI_ALIASING_ON) {\n        /* ANTI-ALIASED STROKE */\n        const float AA_SIZE = 1.0f;\n        NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2);\n        NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2);\n\n        /* allocate vertices and elements  */\n        nk_size i1 = 0;\n        nk_size vertex_offset;\n        nk_size index = list->vertex_count;\n\n        const nk_size idx_count = (thick_line) ?  (count * 18) : (count * 12);\n        const nk_size vtx_count = (thick_line) ? (points_count * 4): (points_count *3);\n\n        void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);\n        nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);\n\n        nk_size size;\n        struct nk_vec2 *normals, *temp;\n        if (!vtx || !ids) return;\n\n        /* temporary allocate normals + points */\n        vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr);\n        nk_buffer_mark(list->vertices, NK_BUFFER_FRONT);\n        size = pnt_size * ((thick_line) ? 5 : 3) * points_count;\n        normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align);\n        if (!normals) return;\n        temp = normals + points_count;\n\n        /* make sure vertex pointer is still correct */\n        vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset);\n\n        /* calculate normals */\n        for (i1 = 0; i1 < count; ++i1) {\n            const nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1);\n            struct nk_vec2 diff = nk_vec2_sub(points[i2], points[i1]);\n            float len;\n\n            /* vec2 inverted length  */\n            len = nk_vec2_len_sqr(diff);\n            if (len != 0.0f)\n                len = NK_INV_SQRT(len);\n            else len = 1.0f;\n\n            diff = nk_vec2_muls(diff, len);\n            normals[i1].x = diff.y;\n            normals[i1].y = -diff.x;\n        }\n\n        if (!closed)\n            normals[points_count-1] = normals[points_count-2];\n\n        if (!thick_line) {\n            nk_size idx1, i;\n            if (!closed) {\n                struct nk_vec2 d;\n                temp[0] = nk_vec2_add(points[0], nk_vec2_muls(normals[0], AA_SIZE));\n                temp[1] = nk_vec2_sub(points[0], nk_vec2_muls(normals[0], AA_SIZE));\n                d = nk_vec2_muls(normals[points_count-1], AA_SIZE);\n                temp[(points_count-1) * 2 + 0] = nk_vec2_add(points[points_count-1], d);\n                temp[(points_count-1) * 2 + 1] = nk_vec2_sub(points[points_count-1], d);\n            }\n\n            /* fill elements */\n            idx1 = index;\n            for (i1 = 0; i1 < count; i1++) {\n                struct nk_vec2 dm;\n                float dmr2;\n                nk_size i2 = ((i1 + 1) == points_count) ? 0 : (i1 + 1);\n                nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 3);\n\n                /* average normals */\n                dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f);\n                dmr2 = dm.x * dm.x + dm.y* dm.y;\n                if (dmr2 > 0.000001f) {\n                    float scale = 1.0f/dmr2;\n                    scale = NK_MIN(100.0f, scale);\n                    dm = nk_vec2_muls(dm, scale);\n                }\n\n                dm = nk_vec2_muls(dm, AA_SIZE);\n                temp[i2*2+0] = nk_vec2_add(points[i2], dm);\n                temp[i2*2+1] = nk_vec2_sub(points[i2], dm);\n\n                ids[0] = (nk_draw_index)(idx2 + 0); ids[1] = (nk_draw_index)(idx1+0);\n                ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2);\n                ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+0);\n                ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1);\n                ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0);\n                ids[10]= (nk_draw_index)(idx2 + 0); ids[11]= (nk_draw_index)(idx2+1);\n                ids += 12;\n                idx1 = idx2;\n            }\n\n            /* fill vertices */\n            for (i = 0; i < points_count; ++i) {\n                const struct nk_vec2 uv = list->config.tex_null.uv;\n                vtx = nk_draw_vertex(vtx, &list->config, points[i], uv, col);\n                vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+0], uv, col_trans);\n                vtx = nk_draw_vertex(vtx, &list->config, temp[i*2+1], uv, col_trans);\n            }\n        } else {\n            nk_size idx1, i;\n            const float half_inner_thickness = (thickness - AA_SIZE) * 0.5f;\n            if (!closed) {\n                struct nk_vec2 d1 = nk_vec2_muls(normals[0], half_inner_thickness + AA_SIZE);\n                struct nk_vec2 d2 = nk_vec2_muls(normals[0], half_inner_thickness);\n\n                temp[0] = nk_vec2_add(points[0], d1);\n                temp[1] = nk_vec2_add(points[0], d2);\n                temp[2] = nk_vec2_sub(points[0], d2);\n                temp[3] = nk_vec2_sub(points[0], d1);\n\n                d1 = nk_vec2_muls(normals[points_count-1], half_inner_thickness + AA_SIZE);\n                d2 = nk_vec2_muls(normals[points_count-1], half_inner_thickness);\n\n                temp[(points_count-1)*4+0] = nk_vec2_add(points[points_count-1], d1);\n                temp[(points_count-1)*4+1] = nk_vec2_add(points[points_count-1], d2);\n                temp[(points_count-1)*4+2] = nk_vec2_sub(points[points_count-1], d2);\n                temp[(points_count-1)*4+3] = nk_vec2_sub(points[points_count-1], d1);\n            }\n\n            /* add all elements */\n            idx1 = index;\n            for (i1 = 0; i1 < count; ++i1) {\n                struct nk_vec2 dm_out, dm_in;\n                const nk_size i2 = ((i1+1) == points_count) ? 0: (i1 + 1);\n                nk_size idx2 = ((i1+1) == points_count) ? index: (idx1 + 4);\n\n                /* average normals */\n                struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(normals[i1], normals[i2]), 0.5f);\n                float dmr2 = dm.x * dm.x + dm.y* dm.y;\n                if (dmr2 > 0.000001f) {\n                    float scale = 1.0f/dmr2;\n                    scale = NK_MIN(100.0f, scale);\n                    dm = nk_vec2_muls(dm, scale);\n                }\n\n                dm_out = nk_vec2_muls(dm, ((half_inner_thickness) + AA_SIZE));\n                dm_in = nk_vec2_muls(dm, half_inner_thickness);\n                temp[i2*4+0] = nk_vec2_add(points[i2], dm_out);\n                temp[i2*4+1] = nk_vec2_add(points[i2], dm_in);\n                temp[i2*4+2] = nk_vec2_sub(points[i2], dm_in);\n                temp[i2*4+3] = nk_vec2_sub(points[i2], dm_out);\n\n                /* add indexes */\n                ids[0] = (nk_draw_index)(idx2 + 1); ids[1] = (nk_draw_index)(idx1+1);\n                ids[2] = (nk_draw_index)(idx1 + 2); ids[3] = (nk_draw_index)(idx1+2);\n                ids[4] = (nk_draw_index)(idx2 + 2); ids[5] = (nk_draw_index)(idx2+1);\n                ids[6] = (nk_draw_index)(idx2 + 1); ids[7] = (nk_draw_index)(idx1+1);\n                ids[8] = (nk_draw_index)(idx1 + 0); ids[9] = (nk_draw_index)(idx1+0);\n                ids[10]= (nk_draw_index)(idx2 + 0); ids[11] = (nk_draw_index)(idx2+1);\n                ids[12]= (nk_draw_index)(idx2 + 2); ids[13] = (nk_draw_index)(idx1+2);\n                ids[14]= (nk_draw_index)(idx1 + 3); ids[15] = (nk_draw_index)(idx1+3);\n                ids[16]= (nk_draw_index)(idx2 + 3); ids[17] = (nk_draw_index)(idx2+2);\n                ids += 18;\n                idx1 = idx2;\n            }\n\n            /* add vertices */\n            for (i = 0; i < points_count; ++i) {\n                const struct nk_vec2 uv = list->config.tex_null.uv;\n                vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+0], uv, col_trans);\n                vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+1], uv, col);\n                vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+2], uv, col);\n                vtx = nk_draw_vertex(vtx, &list->config, temp[i*4+3], uv, col_trans);\n            }\n        }\n        /* free temporary normals + points */\n        nk_buffer_reset(list->vertices, NK_BUFFER_FRONT);\n    } else {\n        /* NON ANTI-ALIASED STROKE */\n        nk_size i1 = 0;\n        nk_size idx = list->vertex_count;\n        const nk_size idx_count = count * 6;\n        const nk_size vtx_count = count * 4;\n        void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);\n        nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);\n        if (!vtx || !ids) return;\n\n        for (i1 = 0; i1 < count; ++i1) {\n            float dx, dy;\n            const struct nk_vec2 uv = list->config.tex_null.uv;\n            const nk_size i2 = ((i1+1) == points_count) ? 0 : i1 + 1;\n            const struct nk_vec2 p1 = points[i1];\n            const struct nk_vec2 p2 = points[i2];\n            struct nk_vec2 diff = nk_vec2_sub(p2, p1);\n            float len;\n\n            /* vec2 inverted length  */\n            len = nk_vec2_len_sqr(diff);\n            if (len != 0.0f)\n                len = NK_INV_SQRT(len);\n            else len = 1.0f;\n            diff = nk_vec2_muls(diff, len);\n\n            /* add vertices */\n            dx = diff.x * (thickness * 0.5f);\n            dy = diff.y * (thickness * 0.5f);\n\n            vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x + dy, p1.y - dx), uv, col);\n            vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x + dy, p2.y - dx), uv, col);\n            vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p2.x - dy, p2.y + dx), uv, col);\n            vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(p1.x - dy, p1.y + dx), uv, col);\n\n            ids[0] = (nk_draw_index)(idx+0); ids[1] = (nk_draw_index)(idx+1);\n            ids[2] = (nk_draw_index)(idx+2); ids[3] = (nk_draw_index)(idx+0);\n            ids[4] = (nk_draw_index)(idx+2); ids[5] = (nk_draw_index)(idx+3);\n\n            ids += 6;\n            idx += 4;\n        }\n    }\n}\nNK_API void\nnk_draw_list_fill_poly_convex(struct nk_draw_list *list,\n    const struct nk_vec2 *points, const unsigned int points_count,\n    struct nk_color color, enum nk_anti_aliasing aliasing)\n{\n    struct nk_colorf col;\n    struct nk_colorf col_trans;\n\n    NK_STORAGE const nk_size pnt_align = NK_ALIGNOF(struct nk_vec2);\n    NK_STORAGE const nk_size pnt_size = sizeof(struct nk_vec2);\n    NK_ASSERT(list);\n    if (!list || points_count < 3) return;\n\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n    nk_draw_list_push_userdata(list, list->userdata);\n#endif\n\n    color.a = (nk_byte)((float)color.a * list->config.global_alpha);\n    nk_color_fv(&col.r, color);\n    col_trans = col;\n    col_trans.a = 0;\n\n    if (aliasing == NK_ANTI_ALIASING_ON) {\n        nk_size i = 0;\n        nk_size i0 = 0;\n        nk_size i1 = 0;\n\n        const float AA_SIZE = 1.0f;\n        nk_size vertex_offset = 0;\n        nk_size index = list->vertex_count;\n\n        const nk_size idx_count = (points_count-2)*3 + points_count*6;\n        const nk_size vtx_count = (points_count*2);\n\n        void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);\n        nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);\n\n        nk_size size = 0;\n        struct nk_vec2 *normals = 0;\n        unsigned int vtx_inner_idx = (unsigned int)(index + 0);\n        unsigned int vtx_outer_idx = (unsigned int)(index + 1);\n        if (!vtx || !ids) return;\n\n        /* temporary allocate normals */\n        vertex_offset = (nk_size)((nk_byte*)vtx - (nk_byte*)list->vertices->memory.ptr);\n        nk_buffer_mark(list->vertices, NK_BUFFER_FRONT);\n        size = pnt_size * points_count;\n        normals = (struct nk_vec2*) nk_buffer_alloc(list->vertices, NK_BUFFER_FRONT, size, pnt_align);\n        if (!normals) return;\n        vtx = (void*)((nk_byte*)list->vertices->memory.ptr + vertex_offset);\n\n        /* add elements */\n        for (i = 2; i < points_count; i++) {\n            ids[0] = (nk_draw_index)(vtx_inner_idx);\n            ids[1] = (nk_draw_index)(vtx_inner_idx + ((i-1) << 1));\n            ids[2] = (nk_draw_index)(vtx_inner_idx + (i << 1));\n            ids += 3;\n        }\n\n        /* compute normals */\n        for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) {\n            struct nk_vec2 p0 = points[i0];\n            struct nk_vec2 p1 = points[i1];\n            struct nk_vec2 diff = nk_vec2_sub(p1, p0);\n\n            /* vec2 inverted length  */\n            float len = nk_vec2_len_sqr(diff);\n            if (len != 0.0f)\n                len = NK_INV_SQRT(len);\n            else len = 1.0f;\n            diff = nk_vec2_muls(diff, len);\n\n            normals[i0].x = diff.y;\n            normals[i0].y = -diff.x;\n        }\n\n        /* add vertices + indexes */\n        for (i0 = points_count-1, i1 = 0; i1 < points_count; i0 = i1++) {\n            const struct nk_vec2 uv = list->config.tex_null.uv;\n            struct nk_vec2 n0 = normals[i0];\n            struct nk_vec2 n1 = normals[i1];\n            struct nk_vec2 dm = nk_vec2_muls(nk_vec2_add(n0, n1), 0.5f);\n            float dmr2 = dm.x*dm.x + dm.y*dm.y;\n            if (dmr2 > 0.000001f) {\n                float scale = 1.0f / dmr2;\n                scale = NK_MIN(scale, 100.0f);\n                dm = nk_vec2_muls(dm, scale);\n            }\n            dm = nk_vec2_muls(dm, AA_SIZE * 0.5f);\n\n            /* add vertices */\n            vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_sub(points[i1], dm), uv, col);\n            vtx = nk_draw_vertex(vtx, &list->config, nk_vec2_add(points[i1], dm), uv, col_trans);\n\n            /* add indexes */\n            ids[0] = (nk_draw_index)(vtx_inner_idx+(i1<<1));\n            ids[1] = (nk_draw_index)(vtx_inner_idx+(i0<<1));\n            ids[2] = (nk_draw_index)(vtx_outer_idx+(i0<<1));\n            ids[3] = (nk_draw_index)(vtx_outer_idx+(i0<<1));\n            ids[4] = (nk_draw_index)(vtx_outer_idx+(i1<<1));\n            ids[5] = (nk_draw_index)(vtx_inner_idx+(i1<<1));\n            ids += 6;\n        }\n        /* free temporary normals + points */\n        nk_buffer_reset(list->vertices, NK_BUFFER_FRONT);\n    } else {\n        nk_size i = 0;\n        nk_size index = list->vertex_count;\n        const nk_size idx_count = (points_count-2)*3;\n        const nk_size vtx_count = points_count;\n        void *vtx = nk_draw_list_alloc_vertices(list, vtx_count);\n        nk_draw_index *ids = nk_draw_list_alloc_elements(list, idx_count);\n\n        if (!vtx || !ids) return;\n        for (i = 0; i < vtx_count; ++i)\n            vtx = nk_draw_vertex(vtx, &list->config, points[i], list->config.tex_null.uv, col);\n        for (i = 2; i < points_count; ++i) {\n            ids[0] = (nk_draw_index)index;\n            ids[1] = (nk_draw_index)(index+ i - 1);\n            ids[2] = (nk_draw_index)(index+i);\n            ids += 3;\n        }\n    }\n}\nNK_API void\nnk_draw_list_path_clear(struct nk_draw_list *list)\n{\n    NK_ASSERT(list);\n    if (!list) return;\n    nk_buffer_reset(list->buffer, NK_BUFFER_FRONT);\n    list->path_count = 0;\n    list->path_offset = 0;\n}\nNK_API void\nnk_draw_list_path_line_to(struct nk_draw_list *list, struct nk_vec2 pos)\n{\n    struct nk_vec2 *points = 0;\n    struct nk_draw_command *cmd = 0;\n    NK_ASSERT(list);\n    if (!list) return;\n    if (!list->cmd_count)\n        nk_draw_list_add_clip(list, nk_null_rect);\n\n    cmd = nk_draw_list_command_last(list);\n    if (cmd && cmd->texture.ptr != list->config.tex_null.texture.ptr)\n        nk_draw_list_push_image(list, list->config.tex_null.texture);\n\n    points = nk_draw_list_alloc_path(list, 1);\n    if (!points) return;\n    points[0] = pos;\n}\nNK_API void\nnk_draw_list_path_arc_to_fast(struct nk_draw_list *list, struct nk_vec2 center,\n    float radius, int a_min, int a_max)\n{\n    int a = 0;\n    NK_ASSERT(list);\n    if (!list) return;\n    if (a_min <= a_max) {\n        for (a = a_min; a <= a_max; a++) {\n            const struct nk_vec2 c = list->circle_vtx[(nk_size)a % NK_LEN(list->circle_vtx)];\n            const float x = center.x + c.x * radius;\n            const float y = center.y + c.y * radius;\n            nk_draw_list_path_line_to(list, nk_vec2(x, y));\n        }\n    }\n}\nNK_API void\nnk_draw_list_path_arc_to(struct nk_draw_list *list, struct nk_vec2 center,\n    float radius, float a_min, float a_max, unsigned int segments)\n{\n    unsigned int i = 0;\n    NK_ASSERT(list);\n    if (!list) return;\n    if (radius == 0.0f) return;\n\n    /*  This algorithm for arc drawing relies on these two trigonometric identities[1]:\n            sin(a + b) = sin(a) * cos(b) + cos(a) * sin(b)\n            cos(a + b) = cos(a) * cos(b) - sin(a) * sin(b)\n\n        Two coordinates (x, y) of a point on a circle centered on\n        the origin can be written in polar form as:\n            x = r * cos(a)\n            y = r * sin(a)\n        where r is the radius of the circle,\n            a is the angle between (x, y) and the origin.\n\n        This allows us to rotate the coordinates around the\n        origin by an angle b using the following transformation:\n            x' = r * cos(a + b) = x * cos(b) - y * sin(b)\n            y' = r * sin(a + b) = y * cos(b) + x * sin(b)\n\n        [1] https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Angle_sum_and_difference_identities\n    */\n    {const float d_angle = (a_max - a_min) / (float)segments;\n    const float sin_d = (float)NK_SIN(d_angle);\n    const float cos_d = (float)NK_COS(d_angle);\n\n    float cx = (float)NK_COS(a_min) * radius;\n    float cy = (float)NK_SIN(a_min) * radius;\n    for(i = 0; i <= segments; ++i) {\n        float new_cx, new_cy;\n        const float x = center.x + cx;\n        const float y = center.y + cy;\n        nk_draw_list_path_line_to(list, nk_vec2(x, y));\n\n        new_cx = cx * cos_d - cy * sin_d;\n        new_cy = cy * cos_d + cx * sin_d;\n        cx = new_cx;\n        cy = new_cy;\n    }}\n}\nNK_API void\nnk_draw_list_path_rect_to(struct nk_draw_list *list, struct nk_vec2 a,\n    struct nk_vec2 b, float rounding)\n{\n    float r;\n    NK_ASSERT(list);\n    if (!list) return;\n    r = rounding;\n    r = NK_MIN(r, ((b.x-a.x) < 0) ? -(b.x-a.x): (b.x-a.x));\n    r = NK_MIN(r, ((b.y-a.y) < 0) ? -(b.y-a.y): (b.y-a.y));\n\n    if (r == 0.0f) {\n        nk_draw_list_path_line_to(list, a);\n        nk_draw_list_path_line_to(list, nk_vec2(b.x,a.y));\n        nk_draw_list_path_line_to(list, b);\n        nk_draw_list_path_line_to(list, nk_vec2(a.x,b.y));\n    } else {\n        nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, a.y + r), r, 6, 9);\n        nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, a.y + r), r, 9, 12);\n        nk_draw_list_path_arc_to_fast(list, nk_vec2(b.x - r, b.y - r), r, 0, 3);\n        nk_draw_list_path_arc_to_fast(list, nk_vec2(a.x + r, b.y - r), r, 3, 6);\n    }\n}\nNK_API void\nnk_draw_list_path_curve_to(struct nk_draw_list *list, struct nk_vec2 p2,\n    struct nk_vec2 p3, struct nk_vec2 p4, unsigned int num_segments)\n{\n    float t_step;\n    unsigned int i_step;\n    struct nk_vec2 p1;\n\n    NK_ASSERT(list);\n    NK_ASSERT(list->path_count);\n    if (!list || !list->path_count) return;\n    num_segments = NK_MAX(num_segments, 1);\n\n    p1 = nk_draw_list_path_last(list);\n    t_step = 1.0f/(float)num_segments;\n    for (i_step = 1; i_step <= num_segments; ++i_step) {\n        float t = t_step * (float)i_step;\n        float u = 1.0f - t;\n        float w1 = u*u*u;\n        float w2 = 3*u*u*t;\n        float w3 = 3*u*t*t;\n        float w4 = t * t *t;\n        float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x;\n        float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y;\n        nk_draw_list_path_line_to(list, nk_vec2(x,y));\n    }\n}\nNK_API void\nnk_draw_list_path_fill(struct nk_draw_list *list, struct nk_color color)\n{\n    struct nk_vec2 *points;\n    NK_ASSERT(list);\n    if (!list) return;\n    points = (struct nk_vec2*)nk_buffer_memory(list->buffer);\n    nk_draw_list_fill_poly_convex(list, points, list->path_count, color, list->config.shape_AA);\n    nk_draw_list_path_clear(list);\n}\nNK_API void\nnk_draw_list_path_stroke(struct nk_draw_list *list, struct nk_color color,\n    enum nk_draw_list_stroke closed, float thickness)\n{\n    struct nk_vec2 *points;\n    NK_ASSERT(list);\n    if (!list) return;\n    points = (struct nk_vec2*)nk_buffer_memory(list->buffer);\n    nk_draw_list_stroke_poly_line(list, points, list->path_count, color,\n        closed, thickness, list->config.line_AA);\n    nk_draw_list_path_clear(list);\n}\nNK_API void\nnk_draw_list_stroke_line(struct nk_draw_list *list, struct nk_vec2 a,\n    struct nk_vec2 b, struct nk_color col, float thickness)\n{\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    if (list->line_AA == NK_ANTI_ALIASING_ON) {\n        nk_draw_list_path_line_to(list, a);\n        nk_draw_list_path_line_to(list, b);\n    } else {\n        nk_draw_list_path_line_to(list, nk_vec2_sub(a,nk_vec2(0.5f,0.5f)));\n        nk_draw_list_path_line_to(list, nk_vec2_sub(b,nk_vec2(0.5f,0.5f)));\n    }\n    nk_draw_list_path_stroke(list,  col, NK_STROKE_OPEN, thickness);\n}\nNK_API void\nnk_draw_list_fill_rect(struct nk_draw_list *list, struct nk_rect rect,\n    struct nk_color col, float rounding)\n{\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n\n    if (list->line_AA == NK_ANTI_ALIASING_ON) {\n        nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y),\n            nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);\n    } else {\n        nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f),\n            nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);\n    } nk_draw_list_path_fill(list,  col);\n}\nNK_API void\nnk_draw_list_stroke_rect(struct nk_draw_list *list, struct nk_rect rect,\n    struct nk_color col, float rounding, float thickness)\n{\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    if (list->line_AA == NK_ANTI_ALIASING_ON) {\n        nk_draw_list_path_rect_to(list, nk_vec2(rect.x, rect.y),\n            nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);\n    } else {\n        nk_draw_list_path_rect_to(list, nk_vec2(rect.x-0.5f, rect.y-0.5f),\n            nk_vec2(rect.x + rect.w, rect.y + rect.h), rounding);\n    } nk_draw_list_path_stroke(list,  col, NK_STROKE_CLOSED, thickness);\n}\nNK_API void\nnk_draw_list_fill_rect_multi_color(struct nk_draw_list *list, struct nk_rect rect,\n    struct nk_color left, struct nk_color top, struct nk_color right,\n    struct nk_color bottom)\n{\n    void *vtx;\n    struct nk_colorf col_left, col_top;\n    struct nk_colorf col_right, col_bottom;\n    nk_draw_index *idx;\n    nk_draw_index index;\n\n    nk_color_fv(&col_left.r, left);\n    nk_color_fv(&col_right.r, right);\n    nk_color_fv(&col_top.r, top);\n    nk_color_fv(&col_bottom.r, bottom);\n\n    NK_ASSERT(list);\n    if (!list) return;\n\n    nk_draw_list_push_image(list, list->config.tex_null.texture);\n    index = (nk_draw_index)list->vertex_count;\n    vtx = nk_draw_list_alloc_vertices(list, 4);\n    idx = nk_draw_list_alloc_elements(list, 6);\n    if (!vtx || !idx) return;\n\n    idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1);\n    idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0);\n    idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3);\n\n    vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y), list->config.tex_null.uv, col_left);\n    vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y), list->config.tex_null.uv, col_top);\n    vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x + rect.w, rect.y + rect.h), list->config.tex_null.uv, col_right);\n    vtx = nk_draw_vertex(vtx, &list->config, nk_vec2(rect.x, rect.y + rect.h), list->config.tex_null.uv, col_bottom);\n}\nNK_API void\nnk_draw_list_fill_triangle(struct nk_draw_list *list, struct nk_vec2 a,\n    struct nk_vec2 b, struct nk_vec2 c, struct nk_color col)\n{\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    nk_draw_list_path_line_to(list, a);\n    nk_draw_list_path_line_to(list, b);\n    nk_draw_list_path_line_to(list, c);\n    nk_draw_list_path_fill(list, col);\n}\nNK_API void\nnk_draw_list_stroke_triangle(struct nk_draw_list *list, struct nk_vec2 a,\n    struct nk_vec2 b, struct nk_vec2 c, struct nk_color col, float thickness)\n{\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    nk_draw_list_path_line_to(list, a);\n    nk_draw_list_path_line_to(list, b);\n    nk_draw_list_path_line_to(list, c);\n    nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);\n}\nNK_API void\nnk_draw_list_fill_circle(struct nk_draw_list *list, struct nk_vec2 center,\n    float radius, struct nk_color col, unsigned int segs)\n{\n    float a_max;\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs;\n    nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs);\n    nk_draw_list_path_fill(list, col);\n}\nNK_API void\nnk_draw_list_stroke_circle(struct nk_draw_list *list, struct nk_vec2 center,\n    float radius, struct nk_color col, unsigned int segs, float thickness)\n{\n    float a_max;\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    a_max = NK_PI * 2.0f * ((float)segs - 1.0f) / (float)segs;\n    nk_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs);\n    nk_draw_list_path_stroke(list, col, NK_STROKE_CLOSED, thickness);\n}\nNK_API void\nnk_draw_list_stroke_curve(struct nk_draw_list *list, struct nk_vec2 p0,\n    struct nk_vec2 cp0, struct nk_vec2 cp1, struct nk_vec2 p1,\n    struct nk_color col, unsigned int segments, float thickness)\n{\n    NK_ASSERT(list);\n    if (!list || !col.a) return;\n    nk_draw_list_path_line_to(list, p0);\n    nk_draw_list_path_curve_to(list, cp0, cp1, p1, segments);\n    nk_draw_list_path_stroke(list, col, NK_STROKE_OPEN, thickness);\n}\nNK_INTERN void\nnk_draw_list_push_rect_uv(struct nk_draw_list *list, struct nk_vec2 a,\n    struct nk_vec2 c, struct nk_vec2 uva, struct nk_vec2 uvc,\n    struct nk_color color)\n{\n    void *vtx;\n    struct nk_vec2 uvb;\n    struct nk_vec2 uvd;\n    struct nk_vec2 b;\n    struct nk_vec2 d;\n\n    struct nk_colorf col;\n    nk_draw_index *idx;\n    nk_draw_index index;\n    NK_ASSERT(list);\n    if (!list) return;\n\n    nk_color_fv(&col.r, color);\n    uvb = nk_vec2(uvc.x, uva.y);\n    uvd = nk_vec2(uva.x, uvc.y);\n    b = nk_vec2(c.x, a.y);\n    d = nk_vec2(a.x, c.y);\n\n    index = (nk_draw_index)list->vertex_count;\n    vtx = nk_draw_list_alloc_vertices(list, 4);\n    idx = nk_draw_list_alloc_elements(list, 6);\n    if (!vtx || !idx) return;\n\n    idx[0] = (nk_draw_index)(index+0); idx[1] = (nk_draw_index)(index+1);\n    idx[2] = (nk_draw_index)(index+2); idx[3] = (nk_draw_index)(index+0);\n    idx[4] = (nk_draw_index)(index+2); idx[5] = (nk_draw_index)(index+3);\n\n    vtx = nk_draw_vertex(vtx, &list->config, a, uva, col);\n    vtx = nk_draw_vertex(vtx, &list->config, b, uvb, col);\n    vtx = nk_draw_vertex(vtx, &list->config, c, uvc, col);\n    vtx = nk_draw_vertex(vtx, &list->config, d, uvd, col);\n}\nNK_API void\nnk_draw_list_add_image(struct nk_draw_list *list, struct nk_image texture,\n    struct nk_rect rect, struct nk_color color)\n{\n    NK_ASSERT(list);\n    if (!list) return;\n    /* push new command with given texture */\n    nk_draw_list_push_image(list, texture.handle);\n    if (nk_image_is_subimage(&texture)) {\n        /* add region inside of the texture  */\n        struct nk_vec2 uv[2];\n        uv[0].x = (float)texture.region[0]/(float)texture.w;\n        uv[0].y = (float)texture.region[1]/(float)texture.h;\n        uv[1].x = (float)(texture.region[0] + texture.region[2])/(float)texture.w;\n        uv[1].y = (float)(texture.region[1] + texture.region[3])/(float)texture.h;\n        nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y),\n            nk_vec2(rect.x + rect.w, rect.y + rect.h),  uv[0], uv[1], color);\n    } else nk_draw_list_push_rect_uv(list, nk_vec2(rect.x, rect.y),\n            nk_vec2(rect.x + rect.w, rect.y + rect.h),\n            nk_vec2(0.0f, 0.0f), nk_vec2(1.0f, 1.0f),color);\n}\nNK_API void\nnk_draw_list_add_text(struct nk_draw_list *list, const struct nk_user_font *font,\n    struct nk_rect rect, const char *text, int len, float font_height,\n    struct nk_color fg)\n{\n    float x = 0;\n    int text_len = 0;\n    nk_rune unicode = 0;\n    nk_rune next = 0;\n    int glyph_len = 0;\n    int next_glyph_len = 0;\n    struct nk_user_font_glyph g;\n\n    NK_ASSERT(list);\n    if (!list || !len || !text) return;\n    if (!NK_INTERSECT(rect.x, rect.y, rect.w, rect.h,\n        list->clip_rect.x, list->clip_rect.y, list->clip_rect.w, list->clip_rect.h)) return;\n\n    nk_draw_list_push_image(list, font->texture);\n    x = rect.x;\n    glyph_len = nk_utf_decode(text, &unicode, len);\n    if (!glyph_len) return;\n\n    /* draw every glyph image */\n    fg.a = (nk_byte)((float)fg.a * list->config.global_alpha);\n    while (text_len < len && glyph_len) {\n        float gx, gy, gh, gw;\n        float char_width = 0;\n        if (unicode == NK_UTF_INVALID) break;\n\n        /* query currently drawn glyph information */\n        next_glyph_len = nk_utf_decode(text + text_len + glyph_len, &next, (int)len - text_len);\n        font->query(font->userdata, font_height, &g, unicode,\n                    (next == NK_UTF_INVALID) ? '\\0' : next);\n\n        /* calculate and draw glyph drawing rectangle and image */\n        gx = x + g.offset.x;\n        gy = rect.y + g.offset.y;\n        gw = g.width; gh = g.height;\n        char_width = g.xadvance;\n        nk_draw_list_push_rect_uv(list, nk_vec2(gx,gy), nk_vec2(gx + gw, gy+ gh),\n            g.uv[0], g.uv[1], fg);\n\n        /* offset next glyph */\n        text_len += glyph_len;\n        x += char_width;\n        glyph_len = next_glyph_len;\n        unicode = next;\n    }\n}\nNK_API nk_flags\nnk_convert(struct nk_context *ctx, struct nk_buffer *cmds,\n    struct nk_buffer *vertices, struct nk_buffer *elements,\n    const struct nk_convert_config *config)\n{\n    nk_flags res = NK_CONVERT_SUCCESS;\n    const struct nk_command *cmd;\n    NK_ASSERT(ctx);\n    NK_ASSERT(cmds);\n    NK_ASSERT(vertices);\n    NK_ASSERT(elements);\n    NK_ASSERT(config);\n    NK_ASSERT(config->vertex_layout);\n    NK_ASSERT(config->vertex_size);\n    if (!ctx || !cmds || !vertices || !elements || !config || !config->vertex_layout)\n        return NK_CONVERT_INVALID_PARAM;\n\n    nk_draw_list_setup(&ctx->draw_list, config, cmds, vertices, elements,\n        config->line_AA, config->shape_AA);\n    nk_foreach(cmd, ctx)\n    {\n#ifdef NK_INCLUDE_COMMAND_USERDATA\n        ctx->draw_list.userdata = cmd->userdata;\n#endif\n        switch (cmd->type) {\n        case NK_COMMAND_NOP: break;\n        case NK_COMMAND_SCISSOR: {\n            const struct nk_command_scissor *s = (const struct nk_command_scissor*)cmd;\n            nk_draw_list_add_clip(&ctx->draw_list, nk_rect(s->x, s->y, s->w, s->h));\n        } break;\n        case NK_COMMAND_LINE: {\n            const struct nk_command_line *l = (const struct nk_command_line*)cmd;\n            nk_draw_list_stroke_line(&ctx->draw_list, nk_vec2(l->begin.x, l->begin.y),\n                nk_vec2(l->end.x, l->end.y), l->color, l->line_thickness);\n        } break;\n        case NK_COMMAND_CURVE: {\n            const struct nk_command_curve *q = (const struct nk_command_curve*)cmd;\n            nk_draw_list_stroke_curve(&ctx->draw_list, nk_vec2(q->begin.x, q->begin.y),\n                nk_vec2(q->ctrl[0].x, q->ctrl[0].y), nk_vec2(q->ctrl[1].x,\n                q->ctrl[1].y), nk_vec2(q->end.x, q->end.y), q->color,\n                config->curve_segment_count, q->line_thickness);\n        } break;\n        case NK_COMMAND_RECT: {\n            const struct nk_command_rect *r = (const struct nk_command_rect*)cmd;\n            nk_draw_list_stroke_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),\n                r->color, (float)r->rounding, r->line_thickness);\n        } break;\n        case NK_COMMAND_RECT_FILLED: {\n            const struct nk_command_rect_filled *r = (const struct nk_command_rect_filled*)cmd;\n            nk_draw_list_fill_rect(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),\n                r->color, (float)r->rounding);\n        } break;\n        case NK_COMMAND_RECT_MULTI_COLOR: {\n            const struct nk_command_rect_multi_color *r = (const struct nk_command_rect_multi_color*)cmd;\n            nk_draw_list_fill_rect_multi_color(&ctx->draw_list, nk_rect(r->x, r->y, r->w, r->h),\n                r->left, r->top, r->right, r->bottom);\n        } break;\n        case NK_COMMAND_CIRCLE: {\n            const struct nk_command_circle *c = (const struct nk_command_circle*)cmd;\n            nk_draw_list_stroke_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2,\n                (float)c->y + (float)c->h/2), (float)c->w/2, c->color,\n                config->circle_segment_count, c->line_thickness);\n        } break;\n        case NK_COMMAND_CIRCLE_FILLED: {\n            const struct nk_command_circle_filled *c = (const struct nk_command_circle_filled *)cmd;\n            nk_draw_list_fill_circle(&ctx->draw_list, nk_vec2((float)c->x + (float)c->w/2,\n                (float)c->y + (float)c->h/2), (float)c->w/2, c->color,\n                config->circle_segment_count);\n        } break;\n        case NK_COMMAND_ARC: {\n            const struct nk_command_arc *c = (const struct nk_command_arc*)cmd;\n            nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy));\n            nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r,\n                c->a[0], c->a[1], config->arc_segment_count);\n            nk_draw_list_path_stroke(&ctx->draw_list, c->color, NK_STROKE_CLOSED, c->line_thickness);\n        } break;\n        case NK_COMMAND_ARC_FILLED: {\n            const struct nk_command_arc_filled *c = (const struct nk_command_arc_filled*)cmd;\n            nk_draw_list_path_line_to(&ctx->draw_list, nk_vec2(c->cx, c->cy));\n            nk_draw_list_path_arc_to(&ctx->draw_list, nk_vec2(c->cx, c->cy), c->r,\n                c->a[0], c->a[1], config->arc_segment_count);\n            nk_draw_list_path_fill(&ctx->draw_list, c->color);\n        } break;\n        case NK_COMMAND_TRIANGLE: {\n            const struct nk_command_triangle *t = (const struct nk_command_triangle*)cmd;\n            nk_draw_list_stroke_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y),\n                nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color,\n                t->line_thickness);\n        } break;\n        case NK_COMMAND_TRIANGLE_FILLED: {\n            const struct nk_command_triangle_filled *t = (const struct nk_command_triangle_filled*)cmd;\n            nk_draw_list_fill_triangle(&ctx->draw_list, nk_vec2(t->a.x, t->a.y),\n                nk_vec2(t->b.x, t->b.y), nk_vec2(t->c.x, t->c.y), t->color);\n        } break;\n        case NK_COMMAND_POLYGON: {\n            int i;\n            const struct nk_command_polygon*p = (const struct nk_command_polygon*)cmd;\n            for (i = 0; i < p->point_count; ++i) {\n                struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);\n                nk_draw_list_path_line_to(&ctx->draw_list, pnt);\n            }\n            nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_CLOSED, p->line_thickness);\n        } break;\n        case NK_COMMAND_POLYGON_FILLED: {\n            int i;\n            const struct nk_command_polygon_filled *p = (const struct nk_command_polygon_filled*)cmd;\n            for (i = 0; i < p->point_count; ++i) {\n                struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);\n                nk_draw_list_path_line_to(&ctx->draw_list, pnt);\n            }\n            nk_draw_list_path_fill(&ctx->draw_list, p->color);\n        } break;\n        case NK_COMMAND_POLYLINE: {\n            int i;\n            const struct nk_command_polyline *p = (const struct nk_command_polyline*)cmd;\n            for (i = 0; i < p->point_count; ++i) {\n                struct nk_vec2 pnt = nk_vec2((float)p->points[i].x, (float)p->points[i].y);\n                nk_draw_list_path_line_to(&ctx->draw_list, pnt);\n            }\n            nk_draw_list_path_stroke(&ctx->draw_list, p->color, NK_STROKE_OPEN, p->line_thickness);\n        } break;\n        case NK_COMMAND_TEXT: {\n            const struct nk_command_text *t = (const struct nk_command_text*)cmd;\n            nk_draw_list_add_text(&ctx->draw_list, t->font, nk_rect(t->x, t->y, t->w, t->h),\n                t->string, t->length, t->height, t->foreground);\n        } break;\n        case NK_COMMAND_IMAGE: {\n            const struct nk_command_image *i = (const struct nk_command_image*)cmd;\n            nk_draw_list_add_image(&ctx->draw_list, i->img, nk_rect(i->x, i->y, i->w, i->h), i->col);\n        } break;\n        case NK_COMMAND_CUSTOM: {\n            const struct nk_command_custom *c = (const struct nk_command_custom*)cmd;\n            c->callback(&ctx->draw_list, c->x, c->y, c->w, c->h, c->callback_data);\n        } break;\n        default: break;\n        }\n    }\n    res |= (cmds->needed > cmds->allocated + (cmds->memory.size - cmds->size)) ? NK_CONVERT_COMMAND_BUFFER_FULL: 0;\n    res |= (vertices->needed > vertices->allocated) ? NK_CONVERT_VERTEX_BUFFER_FULL: 0;\n    res |= (elements->needed > elements->allocated) ? NK_CONVERT_ELEMENT_BUFFER_FULL: 0;\n    return res;\n}\nNK_API const struct nk_draw_command*\nnk__draw_begin(const struct nk_context *ctx,\n    const struct nk_buffer *buffer)\n{\n    return nk__draw_list_begin(&ctx->draw_list, buffer);\n}\nNK_API const struct nk_draw_command*\nnk__draw_end(const struct nk_context *ctx, const struct nk_buffer *buffer)\n{\n    return nk__draw_list_end(&ctx->draw_list, buffer);\n}\nNK_API const struct nk_draw_command*\nnk__draw_next(const struct nk_draw_command *cmd,\n    const struct nk_buffer *buffer, const struct nk_context *ctx)\n{\n    return nk__draw_list_next(cmd, buffer, &ctx->draw_list);\n}\n#endif\n\n"
  },
  {
    "path": "src/nuklear_widget.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              WIDGET\n *\n * ===============================================================*/\nNK_API struct nk_rect\nnk_widget_bounds(const struct nk_context *ctx)\n{\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return nk_rect(0,0,0,0);\n    nk_layout_peek(&bounds, ctx);\n    return bounds;\n}\nNK_API struct nk_vec2\nnk_widget_position(const struct nk_context *ctx)\n{\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return nk_vec2(0,0);\n\n    nk_layout_peek(&bounds, ctx);\n    return nk_vec2(bounds.x, bounds.y);\n}\nNK_API struct nk_vec2\nnk_widget_size(const struct nk_context *ctx)\n{\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return nk_vec2(0,0);\n\n    nk_layout_peek(&bounds, ctx);\n    return nk_vec2(bounds.w, bounds.h);\n}\nNK_API float\nnk_widget_width(const struct nk_context *ctx)\n{\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return 0;\n\n    nk_layout_peek(&bounds, ctx);\n    return bounds.w;\n}\nNK_API float\nnk_widget_height(const struct nk_context *ctx)\n{\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return 0;\n\n    nk_layout_peek(&bounds, ctx);\n    return bounds.h;\n}\nNK_API nk_bool\nnk_widget_is_hovered(const struct nk_context *ctx)\n{\n    struct nk_rect c, v;\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || (ctx->active != ctx->current && !((int)ctx->current->layout->type & (int)NK_PANEL_SET_POPUP)))\n        return 0;\n\n    c = ctx->current->layout->clip;\n    c.x = (float)((int)c.x);\n    c.y = (float)((int)c.y);\n    c.w = (float)((int)c.w);\n    c.h = (float)((int)c.h);\n\n    nk_layout_peek(&bounds, ctx);\n    nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);\n    if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))\n        return 0;\n    return nk_input_is_mouse_hovering_rect(&ctx->input, bounds);\n}\nNK_API nk_bool\nnk_widget_is_mouse_clicked(const struct nk_context *ctx, enum nk_buttons btn)\n{\n    struct nk_rect c, v;\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || (ctx->active != ctx->current && !((int)ctx->current->layout->type & (int)NK_PANEL_SET_POPUP)))\n        return 0;\n\n    c = ctx->current->layout->clip;\n    c.x = (float)((int)c.x);\n    c.y = (float)((int)c.y);\n    c.w = (float)((int)c.w);\n    c.h = (float)((int)c.h);\n\n    nk_layout_peek(&bounds, ctx);\n    nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);\n    if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))\n        return 0;\n    return nk_input_mouse_clicked(&ctx->input, btn, bounds);\n}\nNK_API nk_bool\nnk_widget_has_mouse_click_down(const struct nk_context *ctx, enum nk_buttons btn, nk_bool down)\n{\n    struct nk_rect c, v;\n    struct nk_rect bounds;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout || (ctx->active != ctx->current && !((int)ctx->current->layout->type & (int)NK_PANEL_SET_POPUP)))\n        return 0;\n\n    c = ctx->current->layout->clip;\n    c.x = (float)((int)c.x);\n    c.y = (float)((int)c.y);\n    c.w = (float)((int)c.w);\n    c.h = (float)((int)c.h);\n\n    nk_layout_peek(&bounds, ctx);\n    nk_unify(&v, &c, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h);\n    if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds.x, bounds.y, bounds.w, bounds.h))\n        return 0;\n    return nk_input_has_mouse_click_down_in_rect(&ctx->input, btn, bounds, down);\n}\nNK_API enum nk_widget_layout_states\nnk_widget(struct nk_rect *bounds, const struct nk_context *ctx)\n{\n    struct nk_rect c, v;\n    struct nk_window *win;\n    struct nk_panel *layout;\n    const struct nk_input *in;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return NK_WIDGET_INVALID;\n\n    /* allocate space and check if the widget needs to be updated and drawn */\n    nk_panel_alloc_space(bounds, ctx);\n    win = ctx->current;\n    layout = win->layout;\n    in = &ctx->input;\n    c = layout->clip;\n\n    /*  if one of these triggers you forgot to add an `if` condition around either\n        a window, group, popup, combobox or contextual menu `begin` and `end` block.\n        Example:\n            if (nk_begin(...) {...} nk_end(...); or\n            if (nk_group_begin(...) { nk_group_end(...);} */\n    NK_ASSERT(!(layout->flags & NK_WINDOW_MINIMIZED));\n    NK_ASSERT(!(layout->flags & NK_WINDOW_HIDDEN));\n    NK_ASSERT(!(layout->flags & NK_WINDOW_CLOSED));\n\n    /* need to convert to int here to remove floating point errors */\n    bounds->x = (float)((int)bounds->x);\n    bounds->y = (float)((int)bounds->y);\n    bounds->w = (float)((int)bounds->w);\n    bounds->h = (float)((int)bounds->h);\n\n    c.x = (float)((int)c.x);\n    c.y = (float)((int)c.y);\n    c.w = (float)((int)c.w);\n    c.h = (float)((int)c.h);\n\n    nk_unify(&v, &c, bounds->x, bounds->y, bounds->x + bounds->w, bounds->y + bounds->h);\n    if (!NK_INTERSECT(c.x, c.y, c.w, c.h, bounds->x, bounds->y, bounds->w, bounds->h))\n        return NK_WIDGET_INVALID;\n    if (win->widgets_disabled)\n        return NK_WIDGET_DISABLED;\n    if (!NK_INBOX(in->mouse.pos.x, in->mouse.pos.y, v.x, v.y, v.w, v.h))\n        return NK_WIDGET_ROM;\n    return NK_WIDGET_VALID;\n}\nNK_API enum nk_widget_layout_states\nnk_widget_fitting(struct nk_rect *bounds, const struct nk_context *ctx,\n    struct nk_vec2 item_padding)\n{\n    /* update the bounds to stand without padding  */\n    enum nk_widget_layout_states state;\n    NK_UNUSED(item_padding);\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return NK_WIDGET_INVALID;\n\n    state = nk_widget(bounds, ctx);\n    return state;\n}\nNK_API void\nnk_spacing(struct nk_context *ctx, int cols)\n{\n    struct nk_window *win;\n    struct nk_panel *layout;\n    struct nk_rect none;\n    int i, index, rows;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current || !ctx->current->layout)\n        return;\n\n    /* spacing over row boundaries */\n    win = ctx->current;\n    layout = win->layout;\n    index = (layout->row.index + cols) % layout->row.columns;\n    rows = (layout->row.index + cols) / layout->row.columns;\n    if (rows) {\n        for (i = 0; i < rows; ++i)\n            nk_panel_alloc_row(ctx, win);\n        cols = index;\n    }\n    /* non table layout need to allocate space */\n    if (layout->row.type != NK_LAYOUT_DYNAMIC_FIXED &&\n        layout->row.type != NK_LAYOUT_STATIC_FIXED) {\n        for (i = 0; i < cols; ++i)\n            nk_panel_alloc_space(&none, ctx);\n    } layout->row.index = index;\n}\nNK_API void\nnk_widget_disable_begin(struct nk_context* ctx)\n{\n    struct nk_window* win;\n    struct nk_style* style;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n\n    if (!ctx || !ctx->current)\n        return;\n\n    win = ctx->current;\n    style = &ctx->style;\n\n    win->widgets_disabled = nk_true;\n\n    style->button.color_factor_text = style->button.disabled_factor;\n    style->button.color_factor_background = style->button.disabled_factor;\n    style->chart.color_factor = style->chart.disabled_factor;\n    style->checkbox.color_factor = style->checkbox.disabled_factor;\n    style->combo.color_factor = style->combo.disabled_factor;\n    style->combo.button.color_factor_text = style->combo.button.disabled_factor;\n    style->combo.button.color_factor_background = style->combo.button.disabled_factor;\n    style->contextual_button.color_factor_text = style->contextual_button.disabled_factor;\n    style->contextual_button.color_factor_background = style->contextual_button.disabled_factor;\n    style->edit.color_factor = style->edit.disabled_factor;\n    style->edit.scrollbar.color_factor = style->edit.scrollbar.disabled_factor;\n    style->menu_button.color_factor_text = style->menu_button.disabled_factor;\n    style->menu_button.color_factor_background = style->menu_button.disabled_factor;\n    style->option.color_factor = style->option.disabled_factor;\n    style->progress.color_factor = style->progress.disabled_factor;\n    style->property.color_factor = style->property.disabled_factor;\n    style->property.inc_button.color_factor_text = style->property.inc_button.disabled_factor;\n    style->property.inc_button.color_factor_background = style->property.inc_button.disabled_factor;\n    style->property.dec_button.color_factor_text = style->property.dec_button.disabled_factor;\n    style->property.dec_button.color_factor_background = style->property.dec_button.disabled_factor;\n    style->property.edit.color_factor = style->property.edit.disabled_factor;\n    style->scrollh.color_factor = style->scrollh.disabled_factor;\n    style->scrollh.inc_button.color_factor_text = style->scrollh.inc_button.disabled_factor;\n    style->scrollh.inc_button.color_factor_background = style->scrollh.inc_button.disabled_factor;\n    style->scrollh.dec_button.color_factor_text = style->scrollh.dec_button.disabled_factor;\n    style->scrollh.dec_button.color_factor_background = style->scrollh.dec_button.disabled_factor;\n    style->scrollv.color_factor = style->scrollv.disabled_factor;\n    style->scrollv.inc_button.color_factor_text = style->scrollv.inc_button.disabled_factor;\n    style->scrollv.inc_button.color_factor_background = style->scrollv.inc_button.disabled_factor;\n    style->scrollv.dec_button.color_factor_text = style->scrollv.dec_button.disabled_factor;\n    style->scrollv.dec_button.color_factor_background = style->scrollv.dec_button.disabled_factor;\n    style->selectable.color_factor = style->selectable.disabled_factor;\n    style->slider.color_factor = style->slider.disabled_factor;\n    style->slider.inc_button.color_factor_text = style->slider.inc_button.disabled_factor;\n    style->slider.inc_button.color_factor_background = style->slider.inc_button.disabled_factor;\n    style->slider.dec_button.color_factor_text = style->slider.dec_button.disabled_factor;\n    style->slider.dec_button.color_factor_background = style->slider.dec_button.disabled_factor;\n    style->tab.color_factor = style->tab.disabled_factor;\n    style->tab.node_maximize_button.color_factor_text = style->tab.node_maximize_button.disabled_factor;\n    style->tab.node_minimize_button.color_factor_text = style->tab.node_minimize_button.disabled_factor;\n    style->tab.tab_maximize_button.color_factor_text = style->tab.tab_maximize_button.disabled_factor;\n    style->tab.tab_maximize_button.color_factor_background = style->tab.tab_maximize_button.disabled_factor;\n    style->tab.tab_minimize_button.color_factor_text = style->tab.tab_minimize_button.disabled_factor;\n    style->tab.tab_minimize_button.color_factor_background = style->tab.tab_minimize_button.disabled_factor;\n    style->text.color_factor = style->text.disabled_factor;\n}\nNK_API void\nnk_widget_disable_end(struct nk_context* ctx)\n{\n    struct nk_window* win;\n    struct nk_style* style;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n\n    if (!ctx || !ctx->current)\n        return;\n\n    win = ctx->current;\n    style = &ctx->style;\n\n    win->widgets_disabled = nk_false;\n\n    style->button.color_factor_text = 1.0f;\n    style->button.color_factor_background = 1.0f;\n    style->chart.color_factor = 1.0f;\n    style->checkbox.color_factor = 1.0f;\n    style->combo.color_factor = 1.0f;\n    style->combo.button.color_factor_text = 1.0f;\n    style->combo.button.color_factor_background = 1.0f;\n    style->contextual_button.color_factor_text = 1.0f;\n    style->contextual_button.color_factor_background = 1.0f;\n    style->edit.color_factor = 1.0f;\n    style->edit.scrollbar.color_factor = 1.0f;\n    style->menu_button.color_factor_text = 1.0f;\n    style->menu_button.color_factor_background = 1.0f;\n    style->option.color_factor = 1.0f;\n    style->progress.color_factor = 1.0f;\n    style->property.color_factor = 1.0f;\n    style->property.inc_button.color_factor_text = 1.0f;\n    style->property.inc_button.color_factor_background = 1.0f;\n    style->property.dec_button.color_factor_text = 1.0f;\n    style->property.dec_button.color_factor_background = 1.0f;\n    style->property.edit.color_factor = 1.0f;\n    style->scrollh.color_factor = 1.0f;\n    style->scrollh.inc_button.color_factor_text = 1.0f;\n    style->scrollh.inc_button.color_factor_background = 1.0f;\n    style->scrollh.dec_button.color_factor_text = 1.0f;\n    style->scrollh.dec_button.color_factor_background = 1.0f;\n    style->scrollv.color_factor = 1.0f;\n    style->scrollv.inc_button.color_factor_text = 1.0f;\n    style->scrollv.inc_button.color_factor_background = 1.0f;\n    style->scrollv.dec_button.color_factor_text = 1.0f;\n    style->scrollv.dec_button.color_factor_background = 1.0f;\n    style->selectable.color_factor = 1.0f;\n    style->slider.color_factor = 1.0f;\n    style->slider.inc_button.color_factor_text = 1.0f;\n    style->slider.inc_button.color_factor_background = 1.0f;\n    style->slider.dec_button.color_factor_text = 1.0f;\n    style->slider.dec_button.color_factor_background = 1.0f;\n    style->tab.color_factor = 1.0f;\n    style->tab.node_maximize_button.color_factor_text = 1.0f;\n    style->tab.node_minimize_button.color_factor_text = 1.0f;\n    style->tab.tab_maximize_button.color_factor_text = 1.0f;\n    style->tab.tab_maximize_button.color_factor_background = 1.0f;\n    style->tab.tab_minimize_button.color_factor_text = 1.0f;\n    style->tab.tab_minimize_button.color_factor_background = 1.0f;\n    style->text.color_factor = 1.0f;\n}\n"
  },
  {
    "path": "src/nuklear_window.c",
    "content": "#include \"nuklear.h\"\n#include \"nuklear_internal.h\"\n\n/* ===============================================================\n *\n *                              WINDOW\n *\n * ===============================================================*/\nNK_LIB void*\nnk_create_window(struct nk_context *ctx)\n{\n    struct nk_page_element *elem;\n    elem = nk_create_page_element(ctx);\n    if (!elem) return 0;\n    elem->data.win.seq = ctx->seq;\n    return &elem->data.win;\n}\nNK_LIB void\nnk_free_window(struct nk_context *ctx, struct nk_window *win)\n{\n    /* unlink windows from list */\n    struct nk_table *it = win->tables;\n    if (win->popup.win) {\n        nk_free_window(ctx, win->popup.win);\n        win->popup.win = 0;\n    }\n    win->next = 0;\n    win->prev = 0;\n\n    while (it) {\n        /*free window state tables */\n        struct nk_table *n = it->next;\n        nk_remove_table(win, it);\n        nk_free_table(ctx, it);\n        if (it == win->tables)\n            win->tables = n;\n        it = n;\n    }\n\n    /* link windows into freelist */\n    {union nk_page_data *pd = NK_CONTAINER_OF(win, union nk_page_data, win);\n    struct nk_page_element *pe = NK_CONTAINER_OF(pd, struct nk_page_element, data);\n    nk_free_page_element(ctx, pe);}\n}\nNK_LIB struct nk_window*\nnk_find_window(const struct nk_context *ctx, nk_hash hash, const char *name)\n{\n    struct nk_window *iter;\n    iter = ctx->begin;\n    while (iter) {\n        NK_ASSERT(iter != iter->next);\n        if (iter->name == hash) {\n            int max_len = nk_strlen(iter->name_string);\n            if (!nk_stricmpn(iter->name_string, name, max_len))\n                return iter;\n        }\n        iter = iter->next;\n    }\n    return 0;\n}\nNK_LIB void\nnk_insert_window(struct nk_context *ctx, struct nk_window *win,\n    enum nk_window_insert_location loc)\n{\n    const struct nk_window *iter;\n    NK_ASSERT(ctx);\n    NK_ASSERT(win);\n    if (!win || !ctx) return;\n\n    iter = ctx->begin;\n    while (iter) {\n        NK_ASSERT(iter != iter->next);\n        NK_ASSERT(iter != win);\n        if (iter == win) return;\n        iter = iter->next;\n    }\n\n    if (!ctx->begin) {\n        win->next = 0;\n        win->prev = 0;\n        ctx->begin = win;\n        ctx->end = win;\n        ctx->count = 1;\n        return;\n    }\n    if (loc == NK_INSERT_BACK) {\n        struct nk_window *end;\n        end = ctx->end;\n        end->flags |= NK_WINDOW_ROM;\n        end->next = win;\n        win->prev = ctx->end;\n        win->next = 0;\n        ctx->end = win;\n        ctx->active = ctx->end;\n        ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM;\n    } else {\n        /*ctx->end->flags |= NK_WINDOW_ROM;*/\n        ctx->begin->prev = win;\n        win->next = ctx->begin;\n        win->prev = 0;\n        ctx->begin = win;\n        ctx->begin->flags &= ~(nk_flags)NK_WINDOW_ROM;\n    }\n    ctx->count++;\n}\nNK_LIB void\nnk_remove_window(struct nk_context *ctx, struct nk_window *win)\n{\n    if (win == ctx->begin || win == ctx->end) {\n        if (win == ctx->begin) {\n            ctx->begin = win->next;\n            if (win->next)\n                win->next->prev = 0;\n        }\n        if (win == ctx->end) {\n            ctx->end = win->prev;\n            if (win->prev)\n                win->prev->next = 0;\n        }\n    } else {\n        if (win->next)\n            win->next->prev = win->prev;\n        if (win->prev)\n            win->prev->next = win->next;\n    }\n    if (win == ctx->active || !ctx->active) {\n        ctx->active = ctx->end;\n        if (ctx->end)\n            ctx->end->flags &= ~(nk_flags)NK_WINDOW_ROM;\n    }\n    win->next = 0;\n    win->prev = 0;\n    ctx->count--;\n}\nNK_API nk_bool\nnk_begin(struct nk_context *ctx, const char *title,\n    struct nk_rect bounds, nk_flags flags)\n{\n    return nk_begin_titled(ctx, title, title, bounds, flags);\n}\nNK_API nk_bool\nnk_begin_titled(struct nk_context *ctx, const char *name, const char *title,\n    struct nk_rect bounds, nk_flags flags)\n{\n    struct nk_window *win;\n    struct nk_style *style;\n    nk_hash name_hash;\n    int name_len;\n    int ret = 0;\n\n    NK_ASSERT(ctx);\n    NK_ASSERT(name);\n    NK_ASSERT(title);\n    NK_ASSERT(ctx->style.font && ctx->style.font->width && \"if this triggers you forgot to add a font\");\n    NK_ASSERT(!ctx->current && \"if this triggers you missed a `nk_end` call\");\n    if (!ctx || ctx->current || !title || !name)\n        return 0;\n\n    /* find or create window */\n    style = &ctx->style;\n    name_len = (int)nk_strlen(name);\n    name_hash = nk_murmur_hash(name, (int)name_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, name_hash, name);\n    if (!win) {\n        /* create new window */\n        nk_size name_length = (nk_size)name_len;\n        win = (struct nk_window*)nk_create_window(ctx);\n        NK_ASSERT(win);\n        if (!win) return 0;\n\n        if (flags & NK_WINDOW_BACKGROUND)\n            nk_insert_window(ctx, win, NK_INSERT_FRONT);\n        else nk_insert_window(ctx, win, NK_INSERT_BACK);\n        nk_command_buffer_init(&win->buffer, &ctx->memory, NK_CLIPPING_ON);\n\n        win->flags = flags;\n        win->bounds = bounds;\n        win->name = name_hash;\n        name_length = NK_MIN(name_length, NK_WINDOW_MAX_NAME-1);\n        NK_MEMCPY(win->name_string, name, name_length);\n        win->name_string[name_length] = 0;\n        win->popup.win = 0;\n        win->widgets_disabled = nk_false;\n        if (!ctx->active)\n            ctx->active = win;\n    } else {\n        /* update window */\n        win->flags &= ~(nk_flags)(NK_WINDOW_PRIVATE-1);\n        win->flags |= flags;\n        if (!(win->flags & (NK_WINDOW_MOVABLE | NK_WINDOW_SCALABLE)))\n            win->bounds = bounds;\n        /* If this assert triggers you either:\n         *\n         * I.) Have more than one window with the same name or\n         * II.) You forgot to actually draw the window.\n         *      More specific you did not call `nk_clear` (nk_clear will be\n         *      automatically called for you if you are using one of the\n         *      provided demo backends). */\n        NK_ASSERT(win->seq != ctx->seq);\n        win->seq = ctx->seq;\n        if (!ctx->active && !(win->flags & NK_WINDOW_HIDDEN)) {\n            ctx->active = win;\n            ctx->end = win;\n        }\n    }\n    if (win->flags & NK_WINDOW_HIDDEN) {\n        ctx->current = win;\n        win->layout = 0;\n        return 0;\n    } else nk_start(ctx, win);\n\n    /* window overlapping */\n    if (!(win->flags & NK_WINDOW_HIDDEN) && !(win->flags & NK_WINDOW_NO_INPUT))\n    {\n        int inpanel, ishovered;\n        struct nk_window *iter = win;\n        float h = ctx->style.font->height + 2.0f * style->window.header.padding.y +\n            (2.0f * style->window.header.label_padding.y);\n        struct nk_rect win_bounds = (!(win->flags & NK_WINDOW_MINIMIZED))?\n            win->bounds: nk_rect(win->bounds.x, win->bounds.y, win->bounds.w, h);\n\n        /* activate window if hovered and no other window is overlapping this window */\n        inpanel = nk_input_has_mouse_click_down_in_rect(&ctx->input, NK_BUTTON_LEFT, win_bounds, nk_true);\n        inpanel = inpanel && ctx->input.mouse.buttons[NK_BUTTON_LEFT].clicked;\n        ishovered = nk_input_is_mouse_hovering_rect(&ctx->input, win_bounds);\n        if ((win != ctx->active) && ishovered && !ctx->input.mouse.buttons[NK_BUTTON_LEFT].down) {\n            iter = win->next;\n            while (iter) {\n                struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))?\n                    iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h);\n                if (NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,\n                    iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) &&\n                    (!(iter->flags & NK_WINDOW_HIDDEN)))\n                    break;\n\n                if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) &&\n                    NK_INTERSECT(win->bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,\n                    iter->popup.win->bounds.x, iter->popup.win->bounds.y,\n                    iter->popup.win->bounds.w, iter->popup.win->bounds.h))\n                    break;\n                iter = iter->next;\n            }\n        }\n\n        /* activate window if clicked */\n        if (iter && inpanel && (win != ctx->end)) {\n            iter = win->next;\n            while (iter) {\n                /* try to find a panel with higher priority in the same position */\n                struct nk_rect iter_bounds = (!(iter->flags & NK_WINDOW_MINIMIZED))?\n                iter->bounds: nk_rect(iter->bounds.x, iter->bounds.y, iter->bounds.w, h);\n                if (NK_INBOX(ctx->input.mouse.pos.x, ctx->input.mouse.pos.y,\n                    iter_bounds.x, iter_bounds.y, iter_bounds.w, iter_bounds.h) &&\n                    !(iter->flags & NK_WINDOW_HIDDEN))\n                    break;\n                if (iter->popup.win && iter->popup.active && !(iter->flags & NK_WINDOW_HIDDEN) &&\n                    NK_INTERSECT(win_bounds.x, win_bounds.y, win_bounds.w, win_bounds.h,\n                    iter->popup.win->bounds.x, iter->popup.win->bounds.y,\n                    iter->popup.win->bounds.w, iter->popup.win->bounds.h))\n                    break;\n                iter = iter->next;\n            }\n        }\n        if (iter && !(win->flags & NK_WINDOW_ROM) && (win->flags & NK_WINDOW_BACKGROUND)) {\n            win->flags |= (nk_flags)NK_WINDOW_ROM;\n            iter->flags &= ~(nk_flags)NK_WINDOW_ROM;\n            ctx->active = iter;\n            if (!(iter->flags & NK_WINDOW_BACKGROUND)) {\n                /* current window is active in that position so transfer to top\n                 * at the highest priority in stack */\n                nk_remove_window(ctx, iter);\n                nk_insert_window(ctx, iter, NK_INSERT_BACK);\n            }\n        } else {\n            if (!iter && ctx->end != win) {\n                if (!(win->flags & NK_WINDOW_BACKGROUND)) {\n                    /* current window is active in that position so transfer to top\n                     * at the highest priority in stack */\n                    nk_remove_window(ctx, win);\n                    nk_insert_window(ctx, win, NK_INSERT_BACK);\n                }\n                win->flags &= ~(nk_flags)NK_WINDOW_ROM;\n                ctx->active = win;\n            }\n            if (ctx->end != win && !(win->flags & NK_WINDOW_BACKGROUND))\n                win->flags |= NK_WINDOW_ROM;\n        }\n    }\n    win->layout = (struct nk_panel*)nk_create_panel(ctx);\n    ctx->current = win;\n    ret = nk_panel_begin(ctx, title, NK_PANEL_WINDOW);\n    win->layout->offset_x = &win->scrollbar.x;\n    win->layout->offset_y = &win->scrollbar.y;\n    return ret;\n}\nNK_API void\nnk_end(struct nk_context *ctx)\n{\n    struct nk_panel *layout;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current && \"if this triggers you forgot to call `nk_begin`\");\n    if (!ctx || !ctx->current)\n        return;\n\n    layout = ctx->current->layout;\n    if (!layout || (layout->type == NK_PANEL_WINDOW && (ctx->current->flags & NK_WINDOW_HIDDEN))) {\n        ctx->current = 0;\n        return;\n    }\n    nk_panel_end(ctx);\n    nk_free_panel(ctx, ctx->current->layout);\n    ctx->current = 0;\n}\nNK_API struct nk_rect\nnk_window_get_bounds(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return nk_rect(0,0,0,0);\n    return ctx->current->bounds;\n}\nNK_API struct nk_vec2\nnk_window_get_position(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return nk_vec2(0,0);\n    return nk_vec2(ctx->current->bounds.x, ctx->current->bounds.y);\n}\nNK_API struct nk_vec2\nnk_window_get_size(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return nk_vec2(0,0);\n    return nk_vec2(ctx->current->bounds.w, ctx->current->bounds.h);\n}\nNK_API float\nnk_window_get_width(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return 0;\n    return ctx->current->bounds.w;\n}\nNK_API float\nnk_window_get_height(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return 0;\n    return ctx->current->bounds.h;\n}\nNK_API struct nk_rect\nnk_window_get_content_region(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return nk_rect(0,0,0,0);\n    return ctx->current->layout->clip;\n}\nNK_API struct nk_vec2\nnk_window_get_content_region_min(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current) return nk_vec2(0,0);\n    return nk_vec2(ctx->current->layout->clip.x, ctx->current->layout->clip.y);\n}\nNK_API struct nk_vec2\nnk_window_get_content_region_max(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current) return nk_vec2(0,0);\n    return nk_vec2(ctx->current->layout->clip.x + ctx->current->layout->clip.w,\n        ctx->current->layout->clip.y + ctx->current->layout->clip.h);\n}\nNK_API struct nk_vec2\nnk_window_get_content_region_size(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current) return nk_vec2(0,0);\n    return nk_vec2(ctx->current->layout->clip.w, ctx->current->layout->clip.h);\n}\nNK_API struct nk_command_buffer*\nnk_window_get_canvas(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current) return 0;\n    return &ctx->current->buffer;\n}\nNK_API struct nk_panel*\nnk_window_get_panel(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current) return 0;\n    return ctx->current->layout;\n}\nNK_API void\nnk_window_get_scroll(const struct nk_context *ctx, nk_uint *offset_x, nk_uint *offset_y)\n{\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return ;\n    win = ctx->current;\n    if (offset_x)\n      *offset_x = win->scrollbar.x;\n    if (offset_y)\n      *offset_y = win->scrollbar.y;\n}\nNK_API nk_bool\nnk_window_has_focus(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    NK_ASSERT(ctx->current->layout);\n    if (!ctx || !ctx->current) return 0;\n    return ctx->current == ctx->active;\n}\nNK_API nk_bool\nnk_window_is_hovered(const struct nk_context *ctx)\n{\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current || (ctx->current->flags & NK_WINDOW_HIDDEN))\n        return 0;\n    else {\n        struct nk_rect actual_bounds = ctx->current->bounds;\n        if (ctx->current->flags & NK_WINDOW_MINIMIZED) {\n            actual_bounds.h = ctx->current->layout->header_height;\n        }\n        return nk_input_is_mouse_hovering_rect(&ctx->input, actual_bounds);\n    }\n}\nNK_API nk_bool\nnk_window_is_any_hovered(const struct nk_context *ctx)\n{\n    struct nk_window *iter;\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n    iter = ctx->begin;\n    while (iter) {\n        /* check if window is being hovered */\n        if(!(iter->flags & NK_WINDOW_HIDDEN)) {\n            /* check if window popup is being hovered */\n            if (iter->popup.active && iter->popup.win && nk_input_is_mouse_hovering_rect(&ctx->input, iter->popup.win->bounds))\n                return 1;\n\n            if (iter->flags & NK_WINDOW_MINIMIZED) {\n                struct nk_rect header = iter->bounds;\n                header.h = ctx->style.font->height + 2 * ctx->style.window.header.padding.y;\n                if (nk_input_is_mouse_hovering_rect(&ctx->input, header))\n                    return 1;\n            } else if (nk_input_is_mouse_hovering_rect(&ctx->input, iter->bounds)) {\n                return 1;\n            }\n        }\n        iter = iter->next;\n    }\n    return 0;\n}\nNK_API nk_bool\nnk_item_is_any_active(const struct nk_context *ctx)\n{\n    int any_hovered = nk_window_is_any_hovered(ctx);\n    int any_active = (ctx->last_widget_state & NK_WIDGET_STATE_MODIFIED);\n    return any_hovered || any_active;\n}\nNK_API nk_bool\nnk_window_is_collapsed(const struct nk_context *ctx, const char *name)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (!win) return 0;\n    return win->flags & NK_WINDOW_MINIMIZED;\n}\nNK_API nk_bool\nnk_window_is_closed(const struct nk_context *ctx, const char *name)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return 1;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (!win) return 1;\n    return (win->flags & NK_WINDOW_CLOSED);\n}\nNK_API nk_bool\nnk_window_is_hidden(const struct nk_context *ctx, const char *name)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return 1;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (!win) return 1;\n    return (win->flags & NK_WINDOW_HIDDEN);\n}\nNK_API nk_bool\nnk_window_is_active(const struct nk_context *ctx, const char *name)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return 0;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (!win) return 0;\n    return win == ctx->active;\n}\nNK_API struct nk_window*\nnk_window_find(const struct nk_context *ctx, const char *name)\n{\n    int title_len;\n    nk_hash title_hash;\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    return nk_find_window(ctx, title_hash, name);\n}\nNK_API void\nnk_window_close(struct nk_context *ctx, const char *name)\n{\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    win = nk_window_find(ctx, name);\n    if (!win) return;\n    NK_ASSERT(ctx->current != win && \"You cannot close a currently active window\");\n    if (ctx->current == win) return;\n    win->flags |= NK_WINDOW_HIDDEN;\n    win->flags |= NK_WINDOW_CLOSED;\n}\nNK_API void\nnk_window_set_bounds(struct nk_context *ctx,\n    const char *name, struct nk_rect bounds)\n{\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n    win = nk_window_find(ctx, name);\n    if (!win) return;\n    win->bounds = bounds;\n}\nNK_API void\nnk_window_set_position(struct nk_context *ctx,\n    const char *name, struct nk_vec2 pos)\n{\n    struct nk_window *win = nk_window_find(ctx, name);\n    if (!win) return;\n    win->bounds.x = pos.x;\n    win->bounds.y = pos.y;\n}\nNK_API void\nnk_window_set_size(struct nk_context *ctx,\n    const char *name, struct nk_vec2 size)\n{\n    struct nk_window *win = nk_window_find(ctx, name);\n    if (!win) return;\n    win->bounds.w = size.x;\n    win->bounds.h = size.y;\n}\nNK_API void\nnk_window_set_scroll(struct nk_context *ctx, nk_uint offset_x, nk_uint offset_y)\n{\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    NK_ASSERT(ctx->current);\n    if (!ctx || !ctx->current)\n        return;\n    win = ctx->current;\n    win->scrollbar.x = offset_x;\n    win->scrollbar.y = offset_y;\n}\nNK_API void\nnk_window_collapse(struct nk_context *ctx, const char *name,\n                    enum nk_collapse_states c)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (!win) return;\n    if (c == NK_MINIMIZED)\n        win->flags |= NK_WINDOW_MINIMIZED;\n    else win->flags &= ~(nk_flags)NK_WINDOW_MINIMIZED;\n}\nNK_API void\nnk_window_collapse_if(struct nk_context *ctx, const char *name,\n    enum nk_collapse_states c, int cond)\n{\n    NK_ASSERT(ctx);\n    if (!ctx || !cond) return;\n    nk_window_collapse(ctx, name, c);\n}\nNK_API void\nnk_window_show(struct nk_context *ctx, const char *name, enum nk_show_states s)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (!win) return;\n    if (s == NK_HIDDEN) {\n        win->flags |= NK_WINDOW_HIDDEN;\n    } else win->flags &= ~(nk_flags)NK_WINDOW_HIDDEN;\n}\nNK_API void\nnk_window_show_if(struct nk_context *ctx, const char *name,\n    enum nk_show_states s, int cond)\n{\n    NK_ASSERT(ctx);\n    if (!ctx || !cond) return;\n    nk_window_show(ctx, name, s);\n}\n\nNK_API void\nnk_window_set_focus(struct nk_context *ctx, const char *name)\n{\n    int title_len;\n    nk_hash title_hash;\n    struct nk_window *win;\n    NK_ASSERT(ctx);\n    if (!ctx) return;\n\n    title_len = (int)nk_strlen(name);\n    title_hash = nk_murmur_hash(name, (int)title_len, NK_WINDOW_TITLE);\n    win = nk_find_window(ctx, title_hash, name);\n    if (win && ctx->end != win) {\n        nk_remove_window(ctx, win);\n        nk_insert_window(ctx, win, NK_INSERT_BACK);\n    }\n    ctx->active = win;\n}\nNK_API void\nnk_rule_horizontal(struct nk_context *ctx, struct nk_color color, nk_bool rounding)\n{\n    struct nk_rect space;\n    enum nk_widget_layout_states state = nk_widget(&space, ctx);\n    struct nk_command_buffer *canvas = nk_window_get_canvas(ctx);\n    if (!state) return;\n    nk_fill_rect(canvas, space, rounding && space.h > 1.5f ? space.h / 2.0f : 0, color);\n}\n"
  },
  {
    "path": "src/paq.bat",
    "content": "build.py --macro NK --intro HEADER.md --pub nuklear.h --priv1 nuklear_internal.h,nuklear_math.c,nuklear_util.c,nuklear_color.c,nuklear_utf8.c,nuklear_buffer.c,nuklear_string.c,nuklear_draw.c,nuklear_vertex.c --extern stb_rect_pack.h,stb_truetype.h --priv2 nuklear_font.c,nuklear_input.c,nuklear_style.c,nuklear_context.c,nuklear_pool.c,nuklear_page_element.c,nuklear_table.c,nuklear_panel.c,nuklear_window.c,nuklear_popup.c,nuklear_contextual.c,nuklear_menu.c,nuklear_layout.c,nuklear_tree.c,nuklear_group.c,nuklear_list_view.c,nuklear_widget.c,nuklear_text.c,nuklear_image.c,nuklear_9slice.c,nuklear_button.c,nuklear_toggle.c,nuklear_selectable.c,nuklear_slider.c,nuklear_knob.c,nuklear_progress.c,nuklear_scrollbar.c,nuklear_text_editor.c,nuklear_edit.c,nuklear_property.c,nuklear_chart.c,nuklear_color_picker.c,nuklear_combo.c,nuklear_tooltip.c --outro LICENSE,CHANGELOG,CREDITS > ..\\nuklear.h\n"
  },
  {
    "path": "src/paq.sh",
    "content": "#!/bin/sh\npython3 build.py --macro NK --intro HEADER.md --pub nuklear.h --priv1 nuklear_internal.h,nuklear_math.c,nuklear_util.c,nuklear_color.c,nuklear_utf8.c,nuklear_buffer.c,nuklear_string.c,nuklear_draw.c,nuklear_vertex.c --extern stb_rect_pack.h,stb_truetype.h --priv2 nuklear_font.c,nuklear_input.c,nuklear_style.c,nuklear_context.c,nuklear_pool.c,nuklear_page_element.c,nuklear_table.c,nuklear_panel.c,nuklear_window.c,nuklear_popup.c,nuklear_contextual.c,nuklear_menu.c,nuklear_layout.c,nuklear_tree.c,nuklear_group.c,nuklear_list_view.c,nuklear_widget.c,nuklear_text.c,nuklear_image.c,nuklear_9slice.c,nuklear_button.c,nuklear_toggle.c,nuklear_selectable.c,nuklear_slider.c,nuklear_knob.c,nuklear_progress.c,nuklear_scrollbar.c,nuklear_text_editor.c,nuklear_edit.c,nuklear_property.c,nuklear_chart.c,nuklear_color_picker.c,nuklear_combo.c,nuklear_tooltip.c --outro LICENSE,CHANGELOG,CREDITS > ../nuklear.h\n"
  },
  {
    "path": "src/stb_rect_pack.h",
    "content": "// stb_rect_pack.h - v1.01 - public domain - rectangle packing\n// Sean Barrett 2014\n//\n// Useful for e.g. packing rectangular textures into an atlas.\n// Does not do rotation.\n//\n// Before #including,\n//\n//    #define STB_RECT_PACK_IMPLEMENTATION\n//\n// in the file that you want to have the implementation.\n//\n// Not necessarily the awesomest packing method, but better than\n// the totally naive one in stb_truetype (which is primarily what\n// this is meant to replace).\n//\n// Has only had a few tests run, may have issues.\n//\n// More docs to come.\n//\n// No memory allocations; uses qsort() and assert() from stdlib.\n// Can override those by defining STBRP_SORT and STBRP_ASSERT.\n//\n// This library currently uses the Skyline Bottom-Left algorithm.\n//\n// Please note: better rectangle packers are welcome! Please\n// implement them to the same API, but with a different init\n// function.\n//\n// Credits\n//\n//  Library\n//    Sean Barrett\n//  Minor features\n//    Martins Mozeiko\n//    github:IntellectualKitty\n//\n//  Bugfixes / warning fixes\n//    Jeremy Jaussaud\n//    Fabian Giesen\n//\n// Version history:\n//\n//     1.01  (2021-07-11)  always use large rect mode, expose STBRP__MAXVAL in public section\n//     1.00  (2019-02-25)  avoid small space waste; gracefully fail too-wide rectangles\n//     0.99  (2019-02-07)  warning fixes\n//     0.11  (2017-03-03)  return packing success/fail result\n//     0.10  (2016-10-25)  remove cast-away-const to avoid warnings\n//     0.09  (2016-08-27)  fix compiler warnings\n//     0.08  (2015-09-13)  really fix bug with empty rects (w=0 or h=0)\n//     0.07  (2015-09-13)  fix bug with empty rects (w=0 or h=0)\n//     0.06  (2015-04-15)  added STBRP_SORT to allow replacing qsort\n//     0.05:  added STBRP_ASSERT to allow replacing assert\n//     0.04:  fixed minor bug in STBRP_LARGE_RECTS support\n//     0.01:  initial release\n//\n// LICENSE\n//\n//   See end of file for license information.\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//       INCLUDE SECTION\n//\n\n#ifndef STB_INCLUDE_STB_RECT_PACK_H\n#define STB_INCLUDE_STB_RECT_PACK_H\n\n#define STB_RECT_PACK_VERSION  1\n\n#ifdef STBRP_STATIC\n#define STBRP_DEF static\n#else\n#define STBRP_DEF extern\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\ntypedef struct stbrp_context stbrp_context;\ntypedef struct stbrp_node    stbrp_node;\ntypedef struct stbrp_rect    stbrp_rect;\n\ntypedef int            stbrp_coord;\n\n#define STBRP__MAXVAL  0x7fffffff\n// Mostly for internal use, but this is the maximum supported coordinate value.\n\nSTBRP_DEF int stbrp_pack_rects (stbrp_context *context, stbrp_rect *rects, int num_rects);\n// Assign packed locations to rectangles. The rectangles are of type\n// 'stbrp_rect' defined below, stored in the array 'rects', and there\n// are 'num_rects' many of them.\n//\n// Rectangles which are successfully packed have the 'was_packed' flag\n// set to a non-zero value and 'x' and 'y' store the minimum location\n// on each axis (i.e. bottom-left in cartesian coordinates, top-left\n// if you imagine y increasing downwards). Rectangles which do not fit\n// have the 'was_packed' flag set to 0.\n//\n// You should not try to access the 'rects' array from another thread\n// while this function is running, as the function temporarily reorders\n// the array while it executes.\n//\n// To pack into another rectangle, you need to call stbrp_init_target\n// again. To continue packing into the same rectangle, you can call\n// this function again. Calling this multiple times with multiple rect\n// arrays will probably produce worse packing results than calling it\n// a single time with the full rectangle array, but the option is\n// available.\n//\n// The function returns 1 if all of the rectangles were successfully\n// packed and 0 otherwise.\n\nstruct stbrp_rect\n{\n   // reserved for your use:\n   int            id;\n\n   // input:\n   stbrp_coord    w, h;\n\n   // output:\n   stbrp_coord    x, y;\n   int            was_packed;  // non-zero if valid packing\n\n}; // 16 bytes, nominally\n\n\nSTBRP_DEF void stbrp_init_target (stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes);\n// Initialize a rectangle packer to:\n//    pack a rectangle that is 'width' by 'height' in dimensions\n//    using temporary storage provided by the array 'nodes', which is 'num_nodes' long\n//\n// You must call this function every time you start packing into a new target.\n//\n// There is no \"shutdown\" function. The 'nodes' memory must stay valid for\n// the following stbrp_pack_rects() call (or calls), but can be freed after\n// the call (or calls) finish.\n//\n// Note: to guarantee best results, either:\n//       1. make sure 'num_nodes' >= 'width'\n//   or  2. call stbrp_allow_out_of_mem() defined below with 'allow_out_of_mem = 1'\n//\n// If you don't do either of the above things, widths will be quantized to multiples\n// of small integers to guarantee the algorithm doesn't run out of temporary storage.\n//\n// If you do #2, then the non-quantized algorithm will be used, but the algorithm\n// may run out of temporary storage and be unable to pack some rectangles.\n\nSTBRP_DEF void stbrp_setup_allow_out_of_mem (stbrp_context *context, int allow_out_of_mem);\n// Optionally call this function after init but before doing any packing to\n// change the handling of the out-of-temp-memory scenario, described above.\n// If you call init again, this will be reset to the default (false).\n\n\nSTBRP_DEF void stbrp_setup_heuristic (stbrp_context *context, int heuristic);\n// Optionally select which packing heuristic the library should use. Different\n// heuristics will produce better/worse results for different data sets.\n// If you call init again, this will be reset to the default.\n\nenum\n{\n   STBRP_HEURISTIC_Skyline_default=0,\n   STBRP_HEURISTIC_Skyline_BL_sortHeight = STBRP_HEURISTIC_Skyline_default,\n   STBRP_HEURISTIC_Skyline_BF_sortHeight\n};\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// the details of the following structures don't matter to you, but they must\n// be visible so you can handle the memory allocations for them\n\nstruct stbrp_node\n{\n   stbrp_coord  x,y;\n   stbrp_node  *next;\n};\n\nstruct stbrp_context\n{\n   int width;\n   int height;\n   int align;\n   int init_mode;\n   int heuristic;\n   int num_nodes;\n   stbrp_node *active_head;\n   stbrp_node *free_head;\n   stbrp_node extra[2]; // we allocate two extra nodes so optimal user-node-count is 'width' not 'width+2'\n};\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//     IMPLEMENTATION SECTION\n//\n\n#ifdef STB_RECT_PACK_IMPLEMENTATION\n#ifndef STBRP_SORT\n#include <stdlib.h>\n#define STBRP_SORT qsort\n#endif\n\n#ifndef STBRP_ASSERT\n#include <assert.h>\n#define STBRP_ASSERT assert\n#endif\n\n#ifdef _MSC_VER\n#define STBRP__NOTUSED(v)  (void)(v)\n#define STBRP__CDECL       __cdecl\n#else\n#define STBRP__NOTUSED(v)  (void)sizeof(v)\n#define STBRP__CDECL\n#endif\n\nenum\n{\n   STBRP__INIT_skyline = 1\n};\n\nSTBRP_DEF void stbrp_setup_heuristic(stbrp_context *context, int heuristic)\n{\n   switch (context->init_mode) {\n      case STBRP__INIT_skyline:\n         STBRP_ASSERT(heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight || heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight);\n         context->heuristic = heuristic;\n         break;\n      default:\n         STBRP_ASSERT(0);\n   }\n}\n\nSTBRP_DEF void stbrp_setup_allow_out_of_mem(stbrp_context *context, int allow_out_of_mem)\n{\n   if (allow_out_of_mem)\n      // if it's ok to run out of memory, then don't bother aligning them;\n      // this gives better packing, but may fail due to OOM (even though\n      // the rectangles easily fit). @TODO a smarter approach would be to only\n      // quantize once we've hit OOM, then we could get rid of this parameter.\n      context->align = 1;\n   else {\n      // if it's not ok to run out of memory, then quantize the widths\n      // so that num_nodes is always enough nodes.\n      //\n      // I.e. num_nodes * align >= width\n      //                  align >= width / num_nodes\n      //                  align = ceil(width/num_nodes)\n\n      context->align = (context->width + context->num_nodes-1) / context->num_nodes;\n   }\n}\n\nSTBRP_DEF void stbrp_init_target(stbrp_context *context, int width, int height, stbrp_node *nodes, int num_nodes)\n{\n   int i;\n\n   for (i=0; i < num_nodes-1; ++i)\n      nodes[i].next = &nodes[i+1];\n   nodes[i].next = NULL;\n   context->init_mode = STBRP__INIT_skyline;\n   context->heuristic = STBRP_HEURISTIC_Skyline_default;\n   context->free_head = &nodes[0];\n   context->active_head = &context->extra[0];\n   context->width = width;\n   context->height = height;\n   context->num_nodes = num_nodes;\n   stbrp_setup_allow_out_of_mem(context, 0);\n\n   // node 0 is the full width, node 1 is the sentinel (lets us not store width explicitly)\n   context->extra[0].x = 0;\n   context->extra[0].y = 0;\n   context->extra[0].next = &context->extra[1];\n   context->extra[1].x = (stbrp_coord) width;\n   context->extra[1].y = (1<<30);\n   context->extra[1].next = NULL;\n}\n\n// find minimum y position if it starts at x1\nstatic int stbrp__skyline_find_min_y(stbrp_context *c, stbrp_node *first, int x0, int width, int *pwaste)\n{\n   stbrp_node *node = first;\n   int x1 = x0 + width;\n   int min_y, visited_width, waste_area;\n\n   STBRP__NOTUSED(c);\n\n   STBRP_ASSERT(first->x <= x0);\n\n   #if 0\n   // skip in case we're past the node\n   while (node->next->x <= x0)\n      ++node;\n   #else\n   STBRP_ASSERT(node->next->x > x0); // we ended up handling this in the caller for efficiency\n   #endif\n\n   STBRP_ASSERT(node->x <= x0);\n\n   min_y = 0;\n   waste_area = 0;\n   visited_width = 0;\n   while (node->x < x1) {\n      if (node->y > min_y) {\n         // raise min_y higher.\n         // we've accounted for all waste up to min_y,\n         // but we'll now add more waste for everything we've visited\n         waste_area += visited_width * (node->y - min_y);\n         min_y = node->y;\n         // the first time through, visited_width might be reduced\n         if (node->x < x0)\n            visited_width += node->next->x - x0;\n         else\n            visited_width += node->next->x - node->x;\n      } else {\n         // add waste area\n         int under_width = node->next->x - node->x;\n         if (under_width + visited_width > width)\n            under_width = width - visited_width;\n         waste_area += under_width * (min_y - node->y);\n         visited_width += under_width;\n      }\n      node = node->next;\n   }\n\n   *pwaste = waste_area;\n   return min_y;\n}\n\ntypedef struct\n{\n   int x,y;\n   stbrp_node **prev_link;\n} stbrp__findresult;\n\nstatic stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int width, int height)\n{\n   int best_waste = (1<<30), best_x, best_y = (1 << 30);\n   stbrp__findresult fr;\n   stbrp_node **prev, *node, *tail, **best = NULL;\n\n   // align to multiple of c->align\n   width = (width + c->align - 1);\n   width -= width % c->align;\n   STBRP_ASSERT(width % c->align == 0);\n\n   // if it can't possibly fit, bail immediately\n   if (width > c->width || height > c->height) {\n      fr.prev_link = NULL;\n      fr.x = fr.y = 0;\n      return fr;\n   }\n\n   node = c->active_head;\n   prev = &c->active_head;\n   while (node->x + width <= c->width) {\n      int y,waste;\n      y = stbrp__skyline_find_min_y(c, node, node->x, width, &waste);\n      if (c->heuristic == STBRP_HEURISTIC_Skyline_BL_sortHeight) { // actually just want to test BL\n         // bottom left\n         if (y < best_y) {\n            best_y = y;\n            best = prev;\n         }\n      } else {\n         // best-fit\n         if (y + height <= c->height) {\n            // can only use it if it first vertically\n            if (y < best_y || (y == best_y && waste < best_waste)) {\n               best_y = y;\n               best_waste = waste;\n               best = prev;\n            }\n         }\n      }\n      prev = &node->next;\n      node = node->next;\n   }\n\n   best_x = (best == NULL) ? 0 : (*best)->x;\n\n   // if doing best-fit (BF), we also have to try aligning right edge to each node position\n   //\n   // e.g, if fitting\n   //\n   //     ____________________\n   //    |____________________|\n   //\n   //            into\n   //\n   //   |                         |\n   //   |             ____________|\n   //   |____________|\n   //\n   // then right-aligned reduces waste, but bottom-left BL is always chooses left-aligned\n   //\n   // This makes BF take about 2x the time\n\n   if (c->heuristic == STBRP_HEURISTIC_Skyline_BF_sortHeight) {\n      tail = c->active_head;\n      node = c->active_head;\n      prev = &c->active_head;\n      // find first node that's admissible\n      while (tail->x < width)\n         tail = tail->next;\n      while (tail) {\n         int xpos = tail->x - width;\n         int y,waste;\n         STBRP_ASSERT(xpos >= 0);\n         // find the left position that matches this\n         while (node->next->x <= xpos) {\n            prev = &node->next;\n            node = node->next;\n         }\n         STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);\n         y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);\n         if (y + height <= c->height) {\n            if (y <= best_y) {\n               if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {\n                  best_x = xpos;\n                  STBRP_ASSERT(y <= best_y);\n                  best_y = y;\n                  best_waste = waste;\n                  best = prev;\n               }\n            }\n         }\n         tail = tail->next;\n      }\n   }\n\n   fr.prev_link = best;\n   fr.x = best_x;\n   fr.y = best_y;\n   return fr;\n}\n\nstatic stbrp__findresult stbrp__skyline_pack_rectangle(stbrp_context *context, int width, int height)\n{\n   // find best position according to heuristic\n   stbrp__findresult res = stbrp__skyline_find_best_pos(context, width, height);\n   stbrp_node *node, *cur;\n\n   // bail if:\n   //    1. it failed\n   //    2. the best node doesn't fit (we don't always check this)\n   //    3. we're out of memory\n   if (res.prev_link == NULL || res.y + height > context->height || context->free_head == NULL) {\n      res.prev_link = NULL;\n      return res;\n   }\n\n   // on success, create new node\n   node = context->free_head;\n   node->x = (stbrp_coord) res.x;\n   node->y = (stbrp_coord) (res.y + height);\n\n   context->free_head = node->next;\n\n   // insert the new node into the right starting point, and\n   // let 'cur' point to the remaining nodes needing to be\n   // stitched back in\n\n   cur = *res.prev_link;\n   if (cur->x < res.x) {\n      // preserve the existing one, so start testing with the next one\n      stbrp_node *next = cur->next;\n      cur->next = node;\n      cur = next;\n   } else {\n      *res.prev_link = node;\n   }\n\n   // from here, traverse cur and free the nodes, until we get to one\n   // that shouldn't be freed\n   while (cur->next && cur->next->x <= res.x + width) {\n      stbrp_node *next = cur->next;\n      // move the current node to the free list\n      cur->next = context->free_head;\n      context->free_head = cur;\n      cur = next;\n   }\n\n   // stitch the list back in\n   node->next = cur;\n\n   if (cur->x < res.x + width)\n      cur->x = (stbrp_coord) (res.x + width);\n\n#ifdef _DEBUG\n   cur = context->active_head;\n   while (cur->x < context->width) {\n      STBRP_ASSERT(cur->x < cur->next->x);\n      cur = cur->next;\n   }\n   STBRP_ASSERT(cur->next == NULL);\n\n   {\n      int count=0;\n      cur = context->active_head;\n      while (cur) {\n         cur = cur->next;\n         ++count;\n      }\n      cur = context->free_head;\n      while (cur) {\n         cur = cur->next;\n         ++count;\n      }\n      STBRP_ASSERT(count == context->num_nodes+2);\n   }\n#endif\n\n   return res;\n}\n\nstatic int STBRP__CDECL rect_height_compare(const void *a, const void *b)\n{\n   const stbrp_rect *p = (const stbrp_rect *) a;\n   const stbrp_rect *q = (const stbrp_rect *) b;\n   if (p->h > q->h)\n      return -1;\n   if (p->h < q->h)\n      return  1;\n   return (p->w > q->w) ? -1 : (p->w < q->w);\n}\n\nstatic int STBRP__CDECL rect_original_order(const void *a, const void *b)\n{\n   const stbrp_rect *p = (const stbrp_rect *) a;\n   const stbrp_rect *q = (const stbrp_rect *) b;\n   return (p->was_packed < q->was_packed) ? -1 : (p->was_packed > q->was_packed);\n}\n\nSTBRP_DEF int stbrp_pack_rects(stbrp_context *context, stbrp_rect *rects, int num_rects)\n{\n   int i, all_rects_packed = 1;\n\n   // we use the 'was_packed' field internally to allow sorting/unsorting\n   for (i=0; i < num_rects; ++i) {\n      rects[i].was_packed = i;\n   }\n\n   // sort according to heuristic\n   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_height_compare);\n\n   for (i=0; i < num_rects; ++i) {\n      if (rects[i].w == 0 || rects[i].h == 0) {\n         rects[i].x = rects[i].y = 0;  // empty rect needs no space\n      } else {\n         stbrp__findresult fr = stbrp__skyline_pack_rectangle(context, rects[i].w, rects[i].h);\n         if (fr.prev_link) {\n            rects[i].x = (stbrp_coord) fr.x;\n            rects[i].y = (stbrp_coord) fr.y;\n         } else {\n            rects[i].x = rects[i].y = STBRP__MAXVAL;\n         }\n      }\n   }\n\n   // unsort\n   STBRP_SORT(rects, num_rects, sizeof(rects[0]), rect_original_order);\n\n   // set was_packed flags and all_rects_packed status\n   for (i=0; i < num_rects; ++i) {\n      rects[i].was_packed = !(rects[i].x == STBRP__MAXVAL && rects[i].y == STBRP__MAXVAL);\n      if (!rects[i].was_packed)\n         all_rects_packed = 0;\n   }\n\n   // return the all_rects_packed status\n   return all_rects_packed;\n}\n#endif\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  },
  {
    "path": "src/stb_truetype.h",
    "content": "// stb_truetype.h - v1.26 - public domain\n// authored from 2009-2021 by Sean Barrett / RAD Game Tools\n//\n// =======================================================================\n//\n//    NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES\n//\n// This library does no range checking of the offsets found in the file,\n// meaning an attacker can use it to read arbitrary memory.\n//\n// =======================================================================\n//\n//   This library processes TrueType files:\n//        parse files\n//        extract glyph metrics\n//        extract glyph shapes\n//        render glyphs to one-channel bitmaps with antialiasing (box filter)\n//        render glyphs to one-channel SDF bitmaps (signed-distance field/function)\n//\n//   Todo:\n//        non-MS cmaps\n//        crashproof on bad data\n//        hinting? (no longer patented)\n//        cleartype-style AA?\n//        optimize: use simple memory allocator for intermediates\n//        optimize: build edge-list directly from curves\n//        optimize: rasterize directly from curves?\n//\n// ADDITIONAL CONTRIBUTORS\n//\n//   Mikko Mononen: compound shape support, more cmap formats\n//   Tor Andersson: kerning, subpixel rendering\n//   Dougall Johnson: OpenType / Type 2 font handling\n//   Daniel Ribeiro Maciel: basic GPOS-based kerning\n//\n//   Misc other:\n//       Ryan Gordon\n//       Simon Glass\n//       github:IntellectualKitty\n//       Imanol Celaya\n//       Daniel Ribeiro Maciel\n//\n//   Bug/warning reports/fixes:\n//       \"Zer\" on mollyrocket       Fabian \"ryg\" Giesen   github:NiLuJe\n//       Cass Everitt               Martins Mozeiko       github:aloucks\n//       stoiko (Haemimont Games)   Cap Petschulat        github:oyvindjam\n//       Brian Hook                 Omar Cornut           github:vassvik\n//       Walter van Niftrik         Ryan Griege\n//       David Gow                  Peter LaValle\n//       David Given                Sergey Popov\n//       Ivan-Assen Ivanov          Giumo X. Clanjor\n//       Anthony Pesch              Higor Euripedes\n//       Johan Duparc               Thomas Fields\n//       Hou Qiming                 Derek Vinyard\n//       Rob Loach                  Cort Stratton\n//       Kenney Phillis Jr.         Brian Costabile\n//       Ken Voskuil (kaesve)\n//\n// VERSION HISTORY\n//\n//   1.26 (2021-08-28) fix broken rasterizer\n//   1.25 (2021-07-11) many fixes\n//   1.24 (2020-02-05) fix warning\n//   1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)\n//   1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined\n//   1.21 (2019-02-25) fix warning\n//   1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()\n//   1.19 (2018-02-11) GPOS kerning, STBTT_fmod\n//   1.18 (2018-01-29) add missing function\n//   1.17 (2017-07-23) make more arguments const; doc fix\n//   1.16 (2017-07-12) SDF support\n//   1.15 (2017-03-03) make more arguments const\n//   1.14 (2017-01-16) num-fonts-in-TTC function\n//   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts\n//   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual\n//   1.11 (2016-04-02) fix unused-variable warning\n//   1.10 (2016-04-02) user-defined fabs(); rare memory leak; remove duplicate typedef\n//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use allocation userdata properly\n//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges\n//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;\n//                     variant PackFontRanges to pack and render in separate phases;\n//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);\n//                     fixed an assert() bug in the new rasterizer\n//                     replace assert() with STBTT_assert() in new rasterizer\n//\n//   Full history can be found at the end of this file.\n//\n// LICENSE\n//\n//   See end of file for license information.\n//\n// USAGE\n//\n//   Include this file in whatever places need to refer to it. In ONE C/C++\n//   file, write:\n//      #define STB_TRUETYPE_IMPLEMENTATION\n//   before the #include of this file. This expands out the actual\n//   implementation into that C/C++ file.\n//\n//   To make the implementation private to the file that generates the implementation,\n//      #define STBTT_STATIC\n//\n//   Simple 3D API (don't ship this, but it's fine for tools and quick start)\n//           stbtt_BakeFontBitmap()               -- bake a font to a bitmap for use as texture\n//           stbtt_GetBakedQuad()                 -- compute quad to draw for a given char\n//\n//   Improved 3D API (more shippable):\n//           #include \"stb_rect_pack.h\"           -- optional, but you really want it\n//           stbtt_PackBegin()\n//           stbtt_PackSetOversampling()          -- for improved quality on small fonts\n//           stbtt_PackFontRanges()               -- pack and renders\n//           stbtt_PackEnd()\n//           stbtt_GetPackedQuad()\n//\n//   \"Load\" a font file from a memory buffer (you have to keep the buffer loaded)\n//           stbtt_InitFont()\n//           stbtt_GetFontOffsetForIndex()        -- indexing for TTC font collections\n//           stbtt_GetNumberOfFonts()             -- number of fonts for TTC font collections\n//\n//   Render a unicode codepoint to a bitmap\n//           stbtt_GetCodepointBitmap()           -- allocates and returns a bitmap\n//           stbtt_MakeCodepointBitmap()          -- renders into bitmap you provide\n//           stbtt_GetCodepointBitmapBox()        -- how big the bitmap must be\n//\n//   Character advance/positioning\n//           stbtt_GetCodepointHMetrics()\n//           stbtt_GetFontVMetrics()\n//           stbtt_GetFontVMetricsOS2()\n//           stbtt_GetCodepointKernAdvance()\n//\n//   Starting with version 1.06, the rasterizer was replaced with a new,\n//   faster and generally-more-precise rasterizer. The new rasterizer more\n//   accurately measures pixel coverage for anti-aliasing, except in the case\n//   where multiple shapes overlap, in which case it overestimates the AA pixel\n//   coverage. Thus, anti-aliasing of intersecting shapes may look wrong. If\n//   this turns out to be a problem, you can re-enable the old rasterizer with\n//        #define STBTT_RASTERIZER_VERSION 1\n//   which will incur about a 15% speed hit.\n//\n// ADDITIONAL DOCUMENTATION\n//\n//   Immediately after this block comment are a series of sample programs.\n//\n//   After the sample programs is the \"header file\" section. This section\n//   includes documentation for each API function.\n//\n//   Some important concepts to understand to use this library:\n//\n//      Codepoint\n//         Characters are defined by unicode codepoints, e.g. 65 is\n//         uppercase A, 231 is lowercase c with a cedilla, 0x7e30 is\n//         the hiragana for \"ma\".\n//\n//      Glyph\n//         A visual character shape (every codepoint is rendered as\n//         some glyph)\n//\n//      Glyph index\n//         A font-specific integer ID representing a glyph\n//\n//      Baseline\n//         Glyph shapes are defined relative to a baseline, which is the\n//         bottom of uppercase characters. Characters extend both above\n//         and below the baseline.\n//\n//      Current Point\n//         As you draw text to the screen, you keep track of a \"current point\"\n//         which is the origin of each character. The current point's vertical\n//         position is the baseline. Even \"baked fonts\" use this model.\n//\n//      Vertical Font Metrics\n//         The vertical qualities of the font, used to vertically position\n//         and space the characters. See docs for stbtt_GetFontVMetrics.\n//\n//      Font Size in Pixels or Points\n//         The preferred interface for specifying font sizes in stb_truetype\n//         is to specify how tall the font's vertical extent should be in pixels.\n//         If that sounds good enough, skip the next paragraph.\n//\n//         Most font APIs instead use \"points\", which are a common typographic\n//         measurement for describing font size, defined as 72 points per inch.\n//         stb_truetype provides a point API for compatibility. However, true\n//         \"per inch\" conventions don't make much sense on computer displays\n//         since different monitors have different number of pixels per\n//         inch. For example, Windows traditionally uses a convention that\n//         there are 96 pixels per inch, thus making 'inch' measurements have\n//         nothing to do with inches, and thus effectively defining a point to\n//         be 1.333 pixels. Additionally, the TrueType font data provides\n//         an explicit scale factor to scale a given font's glyphs to points,\n//         but the author has observed that this scale factor is often wrong\n//         for non-commercial fonts, thus making fonts scaled in points\n//         according to the TrueType spec incoherently sized in practice.\n//\n// DETAILED USAGE:\n//\n//  Scale:\n//    Select how high you want the font to be, in points or pixels.\n//    Call ScaleForPixelHeight or ScaleForMappingEmToPixels to compute\n//    a scale factor SF that will be used by all other functions.\n//\n//  Baseline:\n//    You need to select a y-coordinate that is the baseline of where\n//    your text will appear. Call GetFontBoundingBox to get the baseline-relative\n//    bounding box for all characters. SF*-y0 will be the distance in pixels\n//    that the worst-case character could extend above the baseline, so if\n//    you want the top edge of characters to appear at the top of the\n//    screen where y=0, then you would set the baseline to SF*-y0.\n//\n//  Current point:\n//    Set the current point where the first character will appear. The\n//    first character could extend left of the current point; this is font\n//    dependent. You can either choose a current point that is the leftmost\n//    point and hope, or add some padding, or check the bounding box or\n//    left-side-bearing of the first character to be displayed and set\n//    the current point based on that.\n//\n//  Displaying a character:\n//    Compute the bounding box of the character. It will contain signed values\n//    relative to <current_point, baseline>. I.e. if it returns x0,y0,x1,y1,\n//    then the character should be displayed in the rectangle from\n//    <current_point+SF*x0, baseline+SF*y0> to <current_point+SF*x1,baseline+SF*y1).\n//\n//  Advancing for the next character:\n//    Call GlyphHMetrics, and compute 'current_point += SF * advance'.\n//\n//\n// ADVANCED USAGE\n//\n//   Quality:\n//\n//    - Use the functions with Subpixel at the end to allow your characters\n//      to have subpixel positioning. Since the font is anti-aliased, not\n//      hinted, this is very import for quality. (This is not possible with\n//      baked fonts.)\n//\n//    - Kerning is now supported, and if you're supporting subpixel rendering\n//      then kerning is worth using to give your text a polished look.\n//\n//   Performance:\n//\n//    - Convert Unicode codepoints to glyph indexes and operate on the glyphs;\n//      if you don't do this, stb_truetype is forced to do the conversion on\n//      every call.\n//\n//    - There are a lot of memory allocations. We should modify it to take\n//      a temp buffer and allocate from the temp buffer (without freeing),\n//      should help performance a lot.\n//\n// NOTES\n//\n//   The system uses the raw data found in the .ttf file without changing it\n//   and without building auxiliary data structures. This is a bit inefficient\n//   on little-endian systems (the data is big-endian), but assuming you're\n//   caching the bitmaps or glyph shapes this shouldn't be a big deal.\n//\n//   It appears to be very hard to programmatically determine what font a\n//   given file is in a general way. I provide an API for this, but I don't\n//   recommend it.\n//\n//\n// PERFORMANCE MEASUREMENTS FOR 1.06:\n//\n//                      32-bit     64-bit\n//   Previous release:  8.83 s     7.68 s\n//   Pool allocations:  7.72 s     6.34 s\n//   Inline sort     :  6.54 s     5.65 s\n//   New rasterizer  :  5.63 s     5.00 s\n\n//////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////\n////\n////  SAMPLE PROGRAMS\n////\n//\n//  Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless.\n//  See \"tests/truetype_demo_win32.c\" for a complete version.\n#if 0\n#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation\n#include \"stb_truetype.h\"\n\nunsigned char ttf_buffer[1<<20];\nunsigned char temp_bitmap[512*512];\n\nstbtt_bakedchar cdata[96]; // ASCII 32..126 is 95 glyphs\nGLuint ftex;\n\nvoid my_stbtt_initfont(void)\n{\n   fread(ttf_buffer, 1, 1<<20, fopen(\"c:/windows/fonts/times.ttf\", \"rb\"));\n   stbtt_BakeFontBitmap(ttf_buffer,0, 32.0, temp_bitmap,512,512, 32,96, cdata); // no guarantee this fits!\n   // can free ttf_buffer at this point\n   glGenTextures(1, &ftex);\n   glBindTexture(GL_TEXTURE_2D, ftex);\n   glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, 512,512, 0, GL_ALPHA, GL_UNSIGNED_BYTE, temp_bitmap);\n   // can free temp_bitmap at this point\n   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n}\n\nvoid my_stbtt_print(float x, float y, char *text)\n{\n   // assume orthographic projection with units = screen pixels, origin at top left\n   glEnable(GL_BLEND);\n   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n   glEnable(GL_TEXTURE_2D);\n   glBindTexture(GL_TEXTURE_2D, ftex);\n   glBegin(GL_QUADS);\n   while (*text) {\n      if (*text >= 32 && *text < 128) {\n         stbtt_aligned_quad q;\n         stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9\n         glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);\n         glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);\n         glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);\n         glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);\n      }\n      ++text;\n   }\n   glEnd();\n}\n#endif\n//\n//\n//////////////////////////////////////////////////////////////////////////////\n//\n// Complete program (this compiles): get a single bitmap, print as ASCII art\n//\n#if 0\n#include <stdio.h>\n#define STB_TRUETYPE_IMPLEMENTATION  // force following include to generate implementation\n#include \"stb_truetype.h\"\n\nchar ttf_buffer[1<<25];\n\nint main(int argc, char **argv)\n{\n   stbtt_fontinfo font;\n   unsigned char *bitmap;\n   int w,h,i,j,c = (argc > 1 ? atoi(argv[1]) : 'a'), s = (argc > 2 ? atoi(argv[2]) : 20);\n\n   fread(ttf_buffer, 1, 1<<25, fopen(argc > 3 ? argv[3] : \"c:/windows/fonts/arialbd.ttf\", \"rb\"));\n\n   stbtt_InitFont(&font, ttf_buffer, stbtt_GetFontOffsetForIndex(ttf_buffer,0));\n   bitmap = stbtt_GetCodepointBitmap(&font, 0,stbtt_ScaleForPixelHeight(&font, s), c, &w, &h, 0,0);\n\n   for (j=0; j < h; ++j) {\n      for (i=0; i < w; ++i)\n         putchar(\" .:ioVM@\"[bitmap[j*w+i]>>5]);\n      putchar('\\n');\n   }\n   return 0;\n}\n#endif\n//\n// Output:\n//\n//     .ii.\n//    @@@@@@.\n//   V@Mio@@o\n//   :i.  V@V\n//     :oM@@M\n//   :@@@MM@M\n//   @@o  o@M\n//  :@@.  M@M\n//   @@@o@@@@\n//   :M@@V:@@.\n//\n//////////////////////////////////////////////////////////////////////////////\n//\n// Complete program: print \"Hello World!\" banner, with bugs\n//\n#if 0\nchar buffer[24<<20];\nunsigned char screen[20][79];\n\nint main(int arg, char **argv)\n{\n   stbtt_fontinfo font;\n   int i,j,ascent,baseline,ch=0;\n   float scale, xpos=2; // leave a little padding in case the character extends left\n   char *text = \"Heljo World!\"; // intentionally misspelled to show 'lj' brokenness\n\n   fread(buffer, 1, 1000000, fopen(\"c:/windows/fonts/arialbd.ttf\", \"rb\"));\n   stbtt_InitFont(&font, buffer, 0);\n\n   scale = stbtt_ScaleForPixelHeight(&font, 15);\n   stbtt_GetFontVMetrics(&font, &ascent,0,0);\n   baseline = (int) (ascent*scale);\n\n   while (text[ch]) {\n      int advance,lsb,x0,y0,x1,y1;\n      float x_shift = xpos - (float) floor(xpos);\n      stbtt_GetCodepointHMetrics(&font, text[ch], &advance, &lsb);\n      stbtt_GetCodepointBitmapBoxSubpixel(&font, text[ch], scale,scale,x_shift,0, &x0,&y0,&x1,&y1);\n      stbtt_MakeCodepointBitmapSubpixel(&font, &screen[baseline + y0][(int) xpos + x0], x1-x0,y1-y0, 79, scale,scale,x_shift,0, text[ch]);\n      // note that this stomps the old data, so where character boxes overlap (e.g. 'lj') it's wrong\n      // because this API is really for baking character bitmaps into textures. if you want to render\n      // a sequence of characters, you really need to render each bitmap to a temp buffer, then\n      // \"alpha blend\" that into the working buffer\n      xpos += (advance * scale);\n      if (text[ch+1])\n         xpos += scale*stbtt_GetCodepointKernAdvance(&font, text[ch],text[ch+1]);\n      ++ch;\n   }\n\n   for (j=0; j < 20; ++j) {\n      for (i=0; i < 78; ++i)\n         putchar(\" .:ioVM@\"[screen[j][i]>>5]);\n      putchar('\\n');\n   }\n\n   return 0;\n}\n#endif\n\n\n//////////////////////////////////////////////////////////////////////////////\n//////////////////////////////////////////////////////////////////////////////\n////\n////   INTEGRATION WITH YOUR CODEBASE\n////\n////   The following sections allow you to supply alternate definitions\n////   of C library functions used by stb_truetype, e.g. if you don't\n////   link with the C runtime library.\n\n#ifdef STB_TRUETYPE_IMPLEMENTATION\n   // #define your own (u)stbtt_int8/16/32 before including to override this\n   #ifndef stbtt_uint8\n   typedef unsigned char   stbtt_uint8;\n   typedef signed   char   stbtt_int8;\n   typedef unsigned short  stbtt_uint16;\n   typedef signed   short  stbtt_int16;\n   typedef unsigned int    stbtt_uint32;\n   typedef signed   int    stbtt_int32;\n   #endif\n\n   typedef char stbtt__check_size32[sizeof(stbtt_int32)==4 ? 1 : -1];\n   typedef char stbtt__check_size16[sizeof(stbtt_int16)==2 ? 1 : -1];\n\n   // e.g. #define your own STBTT_ifloor/STBTT_iceil() to avoid math.h\n   #ifndef STBTT_ifloor\n   #include <math.h>\n   #define STBTT_ifloor(x)   ((int) floor(x))\n   #define STBTT_iceil(x)    ((int) ceil(x))\n   #endif\n\n   #ifndef STBTT_sqrt\n   #include <math.h>\n   #define STBTT_sqrt(x)      sqrt(x)\n   #define STBTT_pow(x,y)     pow(x,y)\n   #endif\n\n   #ifndef STBTT_fmod\n   #include <math.h>\n   #define STBTT_fmod(x,y)    fmod(x,y)\n   #endif\n\n   #ifndef STBTT_cos\n   #include <math.h>\n   #define STBTT_cos(x)       cos(x)\n   #define STBTT_acos(x)      acos(x)\n   #endif\n\n   #ifndef STBTT_fabs\n   #include <math.h>\n   #define STBTT_fabs(x)      fabs(x)\n   #endif\n\n   // #define your own functions \"STBTT_malloc\" / \"STBTT_free\" to avoid malloc.h\n   #ifndef STBTT_malloc\n   #include <stdlib.h>\n   #define STBTT_malloc(x,u)  ((void)(u),malloc(x))\n   #define STBTT_free(x,u)    ((void)(u),free(x))\n   #endif\n\n   #ifndef STBTT_assert\n   #include <assert.h>\n   #define STBTT_assert(x)    assert(x)\n   #endif\n\n   #ifndef STBTT_strlen\n   #include <string.h>\n   #define STBTT_strlen(x)    strlen(x)\n   #endif\n\n   #ifndef STBTT_memcpy\n   #include <string.h>\n   #define STBTT_memcpy       memcpy\n   #define STBTT_memset       memset\n   #endif\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n///////////////////////////////////////////////////////////////////////////////\n////\n////   INTERFACE\n////\n////\n\n#ifndef __STB_INCLUDE_STB_TRUETYPE_H__\n#define __STB_INCLUDE_STB_TRUETYPE_H__\n\n#ifdef STBTT_STATIC\n#define STBTT_DEF static\n#else\n#define STBTT_DEF extern\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n// private structure\ntypedef struct\n{\n   unsigned char *data;\n   int cursor;\n   int size;\n} stbtt__buf;\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// TEXTURE BAKING API\n//\n// If you use this API, you only have to call two functions ever.\n//\n\ntypedef struct\n{\n   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap\n   float xoff,yoff,xadvance;\n} stbtt_bakedchar;\n\nSTBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)\n                                float pixel_height,                     // height of font in pixels\n                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in\n                                int first_char, int num_chars,          // characters to bake\n                                stbtt_bakedchar *chardata);             // you allocate this, it's num_chars long\n// if return is positive, the first unused row of the bitmap\n// if return is negative, returns the negative of the number of characters that fit\n// if return is 0, no characters fit and no rows were used\n// This uses a very crappy packing.\n\ntypedef struct\n{\n   float x0,y0,s0,t0; // top-left\n   float x1,y1,s1,t1; // bottom-right\n} stbtt_aligned_quad;\n\nSTBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph,  // same data as above\n                               int char_index,             // character to display\n                               float *xpos, float *ypos,   // pointers to current position in screen pixel space\n                               stbtt_aligned_quad *q,      // output: quad to draw\n                               int opengl_fillrule);       // true if opengl fill rule; false if DX9 or earlier\n// Call GetBakedQuad with char_index = 'character - first_char', and it\n// creates the quad you need to draw and advances the current position.\n//\n// The coordinate system used assumes y increases downwards.\n//\n// Characters will extend both above and below the current position;\n// see discussion of \"BASELINE\" above.\n//\n// It's inefficient; you might want to c&p it and optimize it.\n\nSTBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap);\n// Query the font vertical metrics without having to create a font first.\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// NEW TEXTURE BAKING API\n//\n// This provides options for packing multiple fonts into one atlas, not\n// perfectly but better than nothing.\n\ntypedef struct\n{\n   unsigned short x0,y0,x1,y1; // coordinates of bbox in bitmap\n   float xoff,yoff,xadvance;\n   float xoff2,yoff2;\n} stbtt_packedchar;\n\ntypedef struct stbtt_pack_context stbtt_pack_context;\ntypedef struct stbtt_fontinfo stbtt_fontinfo;\n#ifndef STB_RECT_PACK_VERSION\ntypedef struct stbrp_rect stbrp_rect;\n#endif\n\nSTBTT_DEF int  stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int width, int height, int stride_in_bytes, int padding, void *alloc_context);\n// Initializes a packing context stored in the passed-in stbtt_pack_context.\n// Future calls using this context will pack characters into the bitmap passed\n// in here: a 1-channel bitmap that is width * height. stride_in_bytes is\n// the distance from one row to the next (or 0 to mean they are packed tightly\n// together). \"padding\" is the amount of padding to leave between each\n// character (normally you want '1' for bitmaps you'll use as textures with\n// bilinear filtering).\n//\n// Returns 0 on failure, 1 on success.\n\nSTBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc);\n// Cleans up the packing context and frees all memory.\n\n#define STBTT_POINT_SIZE(x)   (-(x))\n\nSTBTT_DEF int  stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,\n                                int first_unicode_char_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range);\n// Creates character bitmaps from the font_index'th font found in fontdata (use\n// font_index=0 if you don't know what that is). It creates num_chars_in_range\n// bitmaps for characters with unicode values starting at first_unicode_char_in_range\n// and increasing. Data for how to render them is stored in chardata_for_range;\n// pass these to stbtt_GetPackedQuad to get back renderable quads.\n//\n// font_size is the full height of the character from ascender to descender,\n// as computed by stbtt_ScaleForPixelHeight. To use a point size as computed\n// by stbtt_ScaleForMappingEmToPixels, wrap the point size in STBTT_POINT_SIZE()\n// and pass that result as 'font_size':\n//       ...,                  20 , ... // font max minus min y is 20 pixels tall\n//       ..., STBTT_POINT_SIZE(20), ... // 'M' is 20 pixels tall\n\ntypedef struct\n{\n   float font_size;\n   int first_unicode_codepoint_in_range;  // if non-zero, then the chars are continuous, and this is the first codepoint\n   int *array_of_unicode_codepoints;       // if non-zero, then this is an array of unicode codepoints\n   int num_chars;\n   stbtt_packedchar *chardata_for_range; // output\n   unsigned char h_oversample, v_oversample; // don't set these, they're used internally\n} stbtt_pack_range;\n\nSTBTT_DEF int  stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges);\n// Creates character bitmaps from multiple ranges of characters stored in\n// ranges. This will usually create a better-packed bitmap than multiple\n// calls to stbtt_PackFontRange. Note that you can call this multiple\n// times within a single PackBegin/PackEnd.\n\nSTBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample);\n// Oversampling a font increases the quality by allowing higher-quality subpixel\n// positioning, and is especially valuable at smaller text sizes.\n//\n// This function sets the amount of oversampling for all following calls to\n// stbtt_PackFontRange(s) or stbtt_PackFontRangesGatherRects for a given\n// pack context. The default (no oversampling) is achieved by h_oversample=1\n// and v_oversample=1. The total number of pixels required is\n// h_oversample*v_oversample larger than the default; for example, 2x2\n// oversampling requires 4x the storage of 1x1. For best results, render\n// oversampled textures with bilinear filtering. Look at the readme in\n// stb/tests/oversample for information about oversampled fonts\n//\n// To use with PackFontRangesGather etc., you must set it before calls\n// call to PackFontRangesGatherRects.\n\nSTBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip);\n// If skip != 0, this tells stb_truetype to skip any codepoints for which\n// there is no corresponding glyph. If skip=0, which is the default, then\n// codepoints without a glyph recived the font's \"missing character\" glyph,\n// typically an empty box by convention.\n\nSTBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph,  // same data as above\n                               int char_index,             // character to display\n                               float *xpos, float *ypos,   // pointers to current position in screen pixel space\n                               stbtt_aligned_quad *q,      // output: quad to draw\n                               int align_to_integer);\n\nSTBTT_DEF int  stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);\nSTBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects);\nSTBTT_DEF int  stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects);\n// Calling these functions in sequence is roughly equivalent to calling\n// stbtt_PackFontRanges(). If you more control over the packing of multiple\n// fonts, or if you want to pack custom data into a font texture, take a look\n// at the source to of stbtt_PackFontRanges() and create a custom version\n// using these functions, e.g. call GatherRects multiple times,\n// building up a single array of rects, then call PackRects once,\n// then call RenderIntoRects repeatedly. This may result in a\n// better packing than calling PackFontRanges multiple times\n// (or it may not).\n\n// this is an opaque structure that you shouldn't mess with which holds\n// all the context needed from PackBegin to PackEnd.\nstruct stbtt_pack_context {\n   void *user_allocator_context;\n   void *pack_info;\n   int   width;\n   int   height;\n   int   stride_in_bytes;\n   int   padding;\n   int   skip_missing;\n   unsigned int   h_oversample, v_oversample;\n   unsigned char *pixels;\n   void  *nodes;\n};\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// FONT LOADING\n//\n//\n\nSTBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data);\n// This function will determine the number of fonts in a font file.  TrueType\n// collection (.ttc) files may contain multiple fonts, while TrueType font\n// (.ttf) files only contain one font. The number of fonts can be used for\n// indexing with the previous function where the index is between zero and one\n// less than the total fonts. If an error occurs, -1 is returned.\n\nSTBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index);\n// Each .ttf/.ttc file may have more than one font. Each font has a sequential\n// index number starting from 0. Call this function to get the font offset for\n// a given index; it returns -1 if the index is out of range. A regular .ttf\n// file will only define one font and it always be at offset 0, so it will\n// return '0' for index 0, and -1 for all other indices.\n\n// The following structure is defined publicly so you can declare one on\n// the stack or as a global or etc, but you should treat it as opaque.\nstruct stbtt_fontinfo\n{\n   void           * userdata;\n   unsigned char  * data;              // pointer to .ttf file\n   int              fontstart;         // offset of start of font\n\n   int numGlyphs;                     // number of glyphs, needed for range checking\n\n   int loca,head,glyf,hhea,hmtx,kern,gpos,svg; // table locations as offset from start of .ttf\n   int index_map;                     // a cmap mapping for our chosen character encoding\n   int indexToLocFormat;              // format needed to map from glyph index to glyph\n\n   stbtt__buf cff;                    // cff font data\n   stbtt__buf charstrings;            // the charstring index\n   stbtt__buf gsubrs;                 // global charstring subroutines index\n   stbtt__buf subrs;                  // private charstring subroutines index\n   stbtt__buf fontdicts;              // array of font dicts\n   stbtt__buf fdselect;               // map from glyph to fontdict\n};\n\nSTBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset);\n// Given an offset into the file that defines a font, this function builds\n// the necessary cached info for the rest of the system. You must allocate\n// the stbtt_fontinfo yourself, and stbtt_InitFont will fill it out. You don't\n// need to do anything special to free it, because the contents are pure\n// value data with no additional data structures. Returns 0 on failure.\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// CHARACTER TO GLYPH-INDEX CONVERSIOn\n\nSTBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint);\n// If you're going to perform multiple operations on the same character\n// and you want a speed-up, call this function with the character you're\n// going to process, then use glyph-based functions instead of the\n// codepoint-based functions.\n// Returns 0 if the character codepoint is not defined in the font.\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// CHARACTER PROPERTIES\n//\n\nSTBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float pixels);\n// computes a scale factor to produce a font whose \"height\" is 'pixels' tall.\n// Height is measured as the distance from the highest ascender to the lowest\n// descender; in other words, it's equivalent to calling stbtt_GetFontVMetrics\n// and computing:\n//       scale = pixels / (ascent - descent)\n// so if you prefer to measure height by the ascent only, use a similar calculation.\n\nSTBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels);\n// computes a scale factor to produce a font whose EM size is mapped to\n// 'pixels' tall. This is probably what traditional APIs compute, but\n// I'm not positive.\n\nSTBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap);\n// ascent is the coordinate above the baseline the font extends; descent\n// is the coordinate below the baseline the font extends (i.e. it is typically negative)\n// lineGap is the spacing between one row's descent and the next row's ascent...\n// so you should advance the vertical position by \"*ascent - *descent + *lineGap\"\n//   these are expressed in unscaled coordinates, so you must multiply by\n//   the scale factor for a given size\n\nSTBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap);\n// analogous to GetFontVMetrics, but returns the \"typographic\" values from the OS/2\n// table (specific to MS/Windows TTF files).\n//\n// Returns 1 on success (table present), 0 on failure.\n\nSTBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1);\n// the bounding box around all possible characters\n\nSTBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing);\n// leftSideBearing is the offset from the current horizontal position to the left edge of the character\n// advanceWidth is the offset from the current horizontal position to the next horizontal position\n//   these are expressed in unscaled coordinates\n\nSTBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2);\n// an additional amount to add to the 'advance' value between ch1 and ch2\n\nSTBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1);\n// Gets the bounding box of the visible part of the glyph, in unscaled coordinates\n\nSTBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing);\nSTBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2);\nSTBTT_DEF int  stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);\n// as above, but takes one or more glyph indices for greater efficiency\n\ntypedef struct stbtt_kerningentry\n{\n   int glyph1; // use stbtt_FindGlyphIndex\n   int glyph2;\n   int advance;\n} stbtt_kerningentry;\n\nSTBTT_DEF int  stbtt_GetKerningTableLength(const stbtt_fontinfo *info);\nSTBTT_DEF int  stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length);\n// Retrieves a complete list of all of the kerning pairs provided by the font\n// stbtt_GetKerningTable never writes more than table_length entries and returns how many entries it did write.\n// The table will be sorted by (a.glyph1 == b.glyph1)?(a.glyph2 < b.glyph2):(a.glyph1 < b.glyph1)\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// GLYPH SHAPES (you probably don't need these, but they have to go before\n// the bitmaps for C declaration-order reasons)\n//\n\n#ifndef STBTT_vmove // you can predefine these to use different values (but why?)\n   enum {\n      STBTT_vmove=1,\n      STBTT_vline,\n      STBTT_vcurve,\n      STBTT_vcubic\n   };\n#endif\n\n#ifndef stbtt_vertex // you can predefine this to use different values\n                   // (we share this with other code at RAD)\n   #define stbtt_vertex_type short // can't use stbtt_int16 because that's not visible in the header file\n   typedef struct\n   {\n      stbtt_vertex_type x,y,cx,cy,cx1,cy1;\n      unsigned char type,padding;\n   } stbtt_vertex;\n#endif\n\nSTBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index);\n// returns non-zero if nothing is drawn for this glyph\n\nSTBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices);\nSTBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **vertices);\n// returns # of vertices and fills *vertices with the pointer to them\n//   these are expressed in \"unscaled\" coordinates\n//\n// The shape is a series of contours. Each one starts with\n// a STBTT_moveto, then consists of a series of mixed\n// STBTT_lineto and STBTT_curveto segments. A lineto\n// draws a line from previous endpoint to its x,y; a curveto\n// draws a quadratic bezier from previous endpoint to\n// its x,y, using cx,cy as the bezier control point.\n\nSTBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);\n// frees the data allocated above\n\nSTBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl);\nSTBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);\nSTBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);\n// fills svg with the character's SVG data.\n// returns data size or 0 if SVG not found.\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// BITMAP RENDERING\n//\n\nSTBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata);\n// frees the bitmap allocated below\n\nSTBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff);\n// allocates a large-enough single-channel 8bpp bitmap and renders the\n// specified character/glyph at the specified scale into it, with\n// antialiasing. 0 is no coverage (transparent), 255 is fully covered (opaque).\n// *width & *height are filled out with the width & height of the bitmap,\n// which is stored left-to-right, top-to-bottom.\n//\n// xoff/yoff are the offset it pixel space from the glyph origin to the top-left of the bitmap\n\nSTBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff);\n// the same as stbtt_GetCodepoitnBitmap, but you can specify a subpixel\n// shift for the character\n\nSTBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint);\n// the same as stbtt_GetCodepointBitmap, but you pass in storage for the bitmap\n// in the form of 'output', with row spacing of 'out_stride' bytes. the bitmap\n// is clipped to out_w/out_h bytes. Call stbtt_GetCodepointBitmapBox to get the\n// width and height and positioning info for it first.\n\nSTBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint);\n// same as stbtt_MakeCodepointBitmap, but you can specify a subpixel\n// shift for the character\n\nSTBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint);\n// same as stbtt_MakeCodepointBitmapSubpixel, but prefiltering\n// is performed (see stbtt_PackSetOversampling)\n\nSTBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);\n// get the bbox of the bitmap centered around the glyph origin; so the\n// bitmap width is ix1-ix0, height is iy1-iy0, and location to place\n// the bitmap top left is (leftSideBearing*scale,iy0).\n// (Note that the bitmap uses y-increases-down, but the shape uses\n// y-increases-up, so CodepointBitmapBox and CodepointBox are inverted.)\n\nSTBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);\n// same as stbtt_GetCodepointBitmapBox, but you can specify a subpixel\n// shift for the character\n\n// the following functions are equivalent to the above functions, but operate\n// on glyph indices instead of Unicode codepoints (for efficiency)\nSTBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff);\nSTBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff);\nSTBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph);\nSTBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph);\nSTBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int glyph);\nSTBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1);\nSTBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1);\n\n\n// @TODO: don't expose this structure\ntypedef struct\n{\n   int w,h,stride;\n   unsigned char *pixels;\n} stbtt__bitmap;\n\n// rasterize a shape with quadratic beziers into a bitmap\nSTBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result,        // 1-channel bitmap to draw into\n                               float flatness_in_pixels,     // allowable error of curve in pixels\n                               stbtt_vertex *vertices,       // array of vertices defining shape\n                               int num_verts,                // number of vertices in above array\n                               float scale_x, float scale_y, // scale applied to input vertices\n                               float shift_x, float shift_y, // translation applied to input vertices\n                               int x_off, int y_off,         // another translation applied to input\n                               int invert,                   // if non-zero, vertically flip shape\n                               void *userdata);              // context for to STBTT_MALLOC\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Signed Distance Function (or Field) rendering\n\nSTBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata);\n// frees the SDF bitmap allocated below\n\nSTBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);\nSTBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff);\n// These functions compute a discretized SDF field for a single character, suitable for storing\n// in a single-channel texture, sampling with bilinear filtering, and testing against\n// larger than some threshold to produce scalable fonts.\n//        info              --  the font\n//        scale             --  controls the size of the resulting SDF bitmap, same as it would be creating a regular bitmap\n//        glyph/codepoint   --  the character to generate the SDF for\n//        padding           --  extra \"pixels\" around the character which are filled with the distance to the character (not 0),\n//                                 which allows effects like bit outlines\n//        onedge_value      --  value 0-255 to test the SDF against to reconstruct the character (i.e. the isocontour of the character)\n//        pixel_dist_scale  --  what value the SDF should increase by when moving one SDF \"pixel\" away from the edge (on the 0..255 scale)\n//                                 if positive, > onedge_value is inside; if negative, < onedge_value is inside\n//        width,height      --  output height & width of the SDF bitmap (including padding)\n//        xoff,yoff         --  output origin of the character\n//        return value      --  a 2D array of bytes 0..255, width*height in size\n//\n// pixel_dist_scale & onedge_value are a scale & bias that allows you to make\n// optimal use of the limited 0..255 for your application, trading off precision\n// and special effects. SDF values outside the range 0..255 are clamped to 0..255.\n//\n// Example:\n//      scale = stbtt_ScaleForPixelHeight(22)\n//      padding = 5\n//      onedge_value = 180\n//      pixel_dist_scale = 180/5.0 = 36.0\n//\n//      This will create an SDF bitmap in which the character is about 22 pixels\n//      high but the whole bitmap is about 22+5+5=32 pixels high. To produce a filled\n//      shape, sample the SDF at each pixel and fill the pixel if the SDF value\n//      is greater than or equal to 180/255. (You'll actually want to antialias,\n//      which is beyond the scope of this example.) Additionally, you can compute\n//      offset outlines (e.g. to stroke the character border inside & outside,\n//      or only outside). For example, to fill outside the character up to 3 SDF\n//      pixels, you would compare against (180-36.0*3)/255 = 72/255. The above\n//      choice of variables maps a range from 5 pixels outside the shape to\n//      2 pixels inside the shape to 0..255; this is intended primarily for apply\n//      outside effects only (the interior range is needed to allow proper\n//      antialiasing of the font at *smaller* sizes)\n//\n// The function computes the SDF analytically at each SDF pixel, not by e.g.\n// building a higher-res bitmap and approximating it. In theory the quality\n// should be as high as possible for an SDF of this size & representation, but\n// unclear if this is true in practice (perhaps building a higher-res bitmap\n// and computing from that can allow drop-out prevention).\n//\n// The algorithm has not been optimized at all, so expect it to be slow\n// if computing lots of characters or very large sizes.\n\n\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// Finding the right font...\n//\n// You should really just solve this offline, keep your own tables\n// of what font is what, and don't try to get it out of the .ttf file.\n// That's because getting it out of the .ttf file is really hard, because\n// the names in the file can appear in many possible encodings, in many\n// possible languages, and e.g. if you need a case-insensitive comparison,\n// the details of that depend on the encoding & language in a complex way\n// (actually underspecified in truetype, but also gigantic).\n//\n// But you can use the provided functions in two possible ways:\n//     stbtt_FindMatchingFont() will use *case-sensitive* comparisons on\n//             unicode-encoded names to try to find the font you want;\n//             you can run this before calling stbtt_InitFont()\n//\n//     stbtt_GetFontNameString() lets you get any of the various strings\n//             from the file yourself and do your own comparisons on them.\n//             You have to have called stbtt_InitFont() first.\n\n\nSTBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags);\n// returns the offset (not index) of the font that matches, or -1 if none\n//   if you use STBTT_MACSTYLE_DONTCARE, use a font name like \"Arial Bold\".\n//   if you use any other flag, use a font name like \"Arial\"; this checks\n//     the 'macStyle' header field; i don't know if fonts set this consistently\n#define STBTT_MACSTYLE_DONTCARE     0\n#define STBTT_MACSTYLE_BOLD         1\n#define STBTT_MACSTYLE_ITALIC       2\n#define STBTT_MACSTYLE_UNDERSCORE   4\n#define STBTT_MACSTYLE_NONE         8   // <= not same as 0, this makes us check the bitfield is 0\n\nSTBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2);\n// returns 1/0 whether the first string interpreted as utf8 is identical to\n// the second string interpreted as big-endian utf16... useful for strings from next func\n\nSTBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID);\n// returns the string (which may be big-endian double byte, e.g. for unicode)\n// and puts the length in bytes in *length.\n//\n// some of the values for the IDs are below; for more see the truetype spec:\n//     http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html\n//     http://www.microsoft.com/typography/otspec/name.htm\n\nenum { // platformID\n   STBTT_PLATFORM_ID_UNICODE   =0,\n   STBTT_PLATFORM_ID_MAC       =1,\n   STBTT_PLATFORM_ID_ISO       =2,\n   STBTT_PLATFORM_ID_MICROSOFT =3\n};\n\nenum { // encodingID for STBTT_PLATFORM_ID_UNICODE\n   STBTT_UNICODE_EID_UNICODE_1_0    =0,\n   STBTT_UNICODE_EID_UNICODE_1_1    =1,\n   STBTT_UNICODE_EID_ISO_10646      =2,\n   STBTT_UNICODE_EID_UNICODE_2_0_BMP=3,\n   STBTT_UNICODE_EID_UNICODE_2_0_FULL=4\n};\n\nenum { // encodingID for STBTT_PLATFORM_ID_MICROSOFT\n   STBTT_MS_EID_SYMBOL        =0,\n   STBTT_MS_EID_UNICODE_BMP   =1,\n   STBTT_MS_EID_SHIFTJIS      =2,\n   STBTT_MS_EID_UNICODE_FULL  =10\n};\n\nenum { // encodingID for STBTT_PLATFORM_ID_MAC; same as Script Manager codes\n   STBTT_MAC_EID_ROMAN        =0,   STBTT_MAC_EID_ARABIC       =4,\n   STBTT_MAC_EID_JAPANESE     =1,   STBTT_MAC_EID_HEBREW       =5,\n   STBTT_MAC_EID_CHINESE_TRAD =2,   STBTT_MAC_EID_GREEK        =6,\n   STBTT_MAC_EID_KOREAN       =3,   STBTT_MAC_EID_RUSSIAN      =7\n};\n\nenum { // languageID for STBTT_PLATFORM_ID_MICROSOFT; same as LCID...\n       // problematic because there are e.g. 16 english LCIDs and 16 arabic LCIDs\n   STBTT_MS_LANG_ENGLISH     =0x0409,   STBTT_MS_LANG_ITALIAN     =0x0410,\n   STBTT_MS_LANG_CHINESE     =0x0804,   STBTT_MS_LANG_JAPANESE    =0x0411,\n   STBTT_MS_LANG_DUTCH       =0x0413,   STBTT_MS_LANG_KOREAN      =0x0412,\n   STBTT_MS_LANG_FRENCH      =0x040c,   STBTT_MS_LANG_RUSSIAN     =0x0419,\n   STBTT_MS_LANG_GERMAN      =0x0407,   STBTT_MS_LANG_SPANISH     =0x0409,\n   STBTT_MS_LANG_HEBREW      =0x040d,   STBTT_MS_LANG_SWEDISH     =0x041D\n};\n\nenum { // languageID for STBTT_PLATFORM_ID_MAC\n   STBTT_MAC_LANG_ENGLISH      =0 ,   STBTT_MAC_LANG_JAPANESE     =11,\n   STBTT_MAC_LANG_ARABIC       =12,   STBTT_MAC_LANG_KOREAN       =23,\n   STBTT_MAC_LANG_DUTCH        =4 ,   STBTT_MAC_LANG_RUSSIAN      =32,\n   STBTT_MAC_LANG_FRENCH       =1 ,   STBTT_MAC_LANG_SPANISH      =6 ,\n   STBTT_MAC_LANG_GERMAN       =2 ,   STBTT_MAC_LANG_SWEDISH      =5 ,\n   STBTT_MAC_LANG_HEBREW       =10,   STBTT_MAC_LANG_CHINESE_SIMPLIFIED =33,\n   STBTT_MAC_LANG_ITALIAN      =3 ,   STBTT_MAC_LANG_CHINESE_TRAD =19\n};\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif // __STB_INCLUDE_STB_TRUETYPE_H__\n\n///////////////////////////////////////////////////////////////////////////////\n///////////////////////////////////////////////////////////////////////////////\n////\n////   IMPLEMENTATION\n////\n////\n\n#ifdef STB_TRUETYPE_IMPLEMENTATION\n\n#ifndef STBTT_MAX_OVERSAMPLE\n#define STBTT_MAX_OVERSAMPLE   8\n#endif\n\n#if STBTT_MAX_OVERSAMPLE > 255\n#error \"STBTT_MAX_OVERSAMPLE cannot be > 255\"\n#endif\n\ntypedef int stbtt__test_oversample_pow2[(STBTT_MAX_OVERSAMPLE & (STBTT_MAX_OVERSAMPLE-1)) == 0 ? 1 : -1];\n\n#ifndef STBTT_RASTERIZER_VERSION\n#define STBTT_RASTERIZER_VERSION 2\n#endif\n\n#ifdef _MSC_VER\n#define STBTT__NOTUSED(v)  (void)(v)\n#else\n#define STBTT__NOTUSED(v)  (void)sizeof(v)\n#endif\n\n//////////////////////////////////////////////////////////////////////////\n//\n// stbtt__buf helpers to parse data from file\n//\n\nstatic stbtt_uint8 stbtt__buf_get8(stbtt__buf *b)\n{\n   if (b->cursor >= b->size)\n      return 0;\n   return b->data[b->cursor++];\n}\n\nstatic stbtt_uint8 stbtt__buf_peek8(stbtt__buf *b)\n{\n   if (b->cursor >= b->size)\n      return 0;\n   return b->data[b->cursor];\n}\n\nstatic void stbtt__buf_seek(stbtt__buf *b, int o)\n{\n   STBTT_assert(!(o > b->size || o < 0));\n   b->cursor = (o > b->size || o < 0) ? b->size : o;\n}\n\nstatic void stbtt__buf_skip(stbtt__buf *b, int o)\n{\n   stbtt__buf_seek(b, b->cursor + o);\n}\n\nstatic stbtt_uint32 stbtt__buf_get(stbtt__buf *b, int n)\n{\n   stbtt_uint32 v = 0;\n   int i;\n   STBTT_assert(n >= 1 && n <= 4);\n   for (i = 0; i < n; i++)\n      v = (v << 8) | stbtt__buf_get8(b);\n   return v;\n}\n\nstatic stbtt__buf stbtt__new_buf(const void *p, size_t size)\n{\n   stbtt__buf r;\n   STBTT_assert(size < 0x40000000);\n   r.data = (stbtt_uint8*) p;\n   r.size = (int) size;\n   r.cursor = 0;\n   return r;\n}\n\n#define stbtt__buf_get16(b)  stbtt__buf_get((b), 2)\n#define stbtt__buf_get32(b)  stbtt__buf_get((b), 4)\n\nstatic stbtt__buf stbtt__buf_range(const stbtt__buf *b, int o, int s)\n{\n   stbtt__buf r = stbtt__new_buf(NULL, 0);\n   if (o < 0 || s < 0 || o > b->size || s > b->size - o) return r;\n   r.data = b->data + o;\n   r.size = s;\n   return r;\n}\n\nstatic stbtt__buf stbtt__cff_get_index(stbtt__buf *b)\n{\n   int count, start, offsize;\n   start = b->cursor;\n   count = stbtt__buf_get16(b);\n   if (count) {\n      offsize = stbtt__buf_get8(b);\n      STBTT_assert(offsize >= 1 && offsize <= 4);\n      stbtt__buf_skip(b, offsize * count);\n      stbtt__buf_skip(b, stbtt__buf_get(b, offsize) - 1);\n   }\n   return stbtt__buf_range(b, start, b->cursor - start);\n}\n\nstatic stbtt_uint32 stbtt__cff_int(stbtt__buf *b)\n{\n   int b0 = stbtt__buf_get8(b);\n   if (b0 >= 32 && b0 <= 246)       return b0 - 139;\n   else if (b0 >= 247 && b0 <= 250) return (b0 - 247)*256 + stbtt__buf_get8(b) + 108;\n   else if (b0 >= 251 && b0 <= 254) return -(b0 - 251)*256 - stbtt__buf_get8(b) - 108;\n   else if (b0 == 28)               return stbtt__buf_get16(b);\n   else if (b0 == 29)               return stbtt__buf_get32(b);\n   STBTT_assert(0);\n   return 0;\n}\n\nstatic void stbtt__cff_skip_operand(stbtt__buf *b) {\n   int v, b0 = stbtt__buf_peek8(b);\n   STBTT_assert(b0 >= 28);\n   if (b0 == 30) {\n      stbtt__buf_skip(b, 1);\n      while (b->cursor < b->size) {\n         v = stbtt__buf_get8(b);\n         if ((v & 0xF) == 0xF || (v >> 4) == 0xF)\n            break;\n      }\n   } else {\n      stbtt__cff_int(b);\n   }\n}\n\nstatic stbtt__buf stbtt__dict_get(stbtt__buf *b, int key)\n{\n   stbtt__buf_seek(b, 0);\n   while (b->cursor < b->size) {\n      int start = b->cursor, end, op;\n      while (stbtt__buf_peek8(b) >= 28)\n         stbtt__cff_skip_operand(b);\n      end = b->cursor;\n      op = stbtt__buf_get8(b);\n      if (op == 12)  op = stbtt__buf_get8(b) | 0x100;\n      if (op == key) return stbtt__buf_range(b, start, end-start);\n   }\n   return stbtt__buf_range(b, 0, 0);\n}\n\nstatic void stbtt__dict_get_ints(stbtt__buf *b, int key, int outcount, stbtt_uint32 *out)\n{\n   int i;\n   stbtt__buf operands = stbtt__dict_get(b, key);\n   for (i = 0; i < outcount && operands.cursor < operands.size; i++)\n      out[i] = stbtt__cff_int(&operands);\n}\n\nstatic int stbtt__cff_index_count(stbtt__buf *b)\n{\n   stbtt__buf_seek(b, 0);\n   return stbtt__buf_get16(b);\n}\n\nstatic stbtt__buf stbtt__cff_index_get(stbtt__buf b, int i)\n{\n   int count, offsize, start, end;\n   stbtt__buf_seek(&b, 0);\n   count = stbtt__buf_get16(&b);\n   offsize = stbtt__buf_get8(&b);\n   STBTT_assert(i >= 0 && i < count);\n   STBTT_assert(offsize >= 1 && offsize <= 4);\n   stbtt__buf_skip(&b, i*offsize);\n   start = stbtt__buf_get(&b, offsize);\n   end = stbtt__buf_get(&b, offsize);\n   return stbtt__buf_range(&b, 2+(count+1)*offsize+start, end - start);\n}\n\n//////////////////////////////////////////////////////////////////////////\n//\n// accessors to parse data from file\n//\n\n// on platforms that don't allow misaligned reads, if we want to allow\n// truetype fonts that aren't padded to alignment, define ALLOW_UNALIGNED_TRUETYPE\n\n#define ttBYTE(p)     (* (stbtt_uint8 *) (p))\n#define ttCHAR(p)     (* (stbtt_int8 *) (p))\n#define ttFixed(p)    ttLONG(p)\n\nstatic stbtt_uint16 ttUSHORT(stbtt_uint8 *p) { return p[0]*256 + p[1]; }\nstatic stbtt_int16 ttSHORT(stbtt_uint8 *p)   { return p[0]*256 + p[1]; }\nstatic stbtt_uint32 ttULONG(stbtt_uint8 *p)  { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }\nstatic stbtt_int32 ttLONG(stbtt_uint8 *p)    { return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; }\n\n#define stbtt_tag4(p,c0,c1,c2,c3) ((p)[0] == (c0) && (p)[1] == (c1) && (p)[2] == (c2) && (p)[3] == (c3))\n#define stbtt_tag(p,str)           stbtt_tag4(p,str[0],str[1],str[2],str[3])\n\nstatic int stbtt__isfont(stbtt_uint8 *font)\n{\n   // check the version number\n   if (stbtt_tag4(font, '1',0,0,0))  return 1; // TrueType 1\n   if (stbtt_tag(font, \"typ1\"))   return 1; // TrueType with type 1 font -- we don't support this!\n   if (stbtt_tag(font, \"OTTO\"))   return 1; // OpenType with CFF\n   if (stbtt_tag4(font, 0,1,0,0)) return 1; // OpenType 1.0\n   if (stbtt_tag(font, \"true\"))   return 1; // Apple specification for TrueType fonts\n   return 0;\n}\n\n// @OPTIMIZE: binary search\nstatic stbtt_uint32 stbtt__find_table(stbtt_uint8 *data, stbtt_uint32 fontstart, const char *tag)\n{\n   stbtt_int32 num_tables = ttUSHORT(data+fontstart+4);\n   stbtt_uint32 tabledir = fontstart + 12;\n   stbtt_int32 i;\n   for (i=0; i < num_tables; ++i) {\n      stbtt_uint32 loc = tabledir + 16*i;\n      if (stbtt_tag(data+loc+0, tag))\n         return ttULONG(data+loc+8);\n   }\n   return 0;\n}\n\nstatic int stbtt_GetFontOffsetForIndex_internal(unsigned char *font_collection, int index)\n{\n   // if it's just a font, there's only one valid index\n   if (stbtt__isfont(font_collection))\n      return index == 0 ? 0 : -1;\n\n   // check if it's a TTC\n   if (stbtt_tag(font_collection, \"ttcf\")) {\n      // version 1?\n      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {\n         stbtt_int32 n = ttLONG(font_collection+8);\n         if (index >= n)\n            return -1;\n         return ttULONG(font_collection+12+index*4);\n      }\n   }\n   return -1;\n}\n\nstatic int stbtt_GetNumberOfFonts_internal(unsigned char *font_collection)\n{\n   // if it's just a font, there's only one valid font\n   if (stbtt__isfont(font_collection))\n      return 1;\n\n   // check if it's a TTC\n   if (stbtt_tag(font_collection, \"ttcf\")) {\n      // version 1?\n      if (ttULONG(font_collection+4) == 0x00010000 || ttULONG(font_collection+4) == 0x00020000) {\n         return ttLONG(font_collection+8);\n      }\n   }\n   return 0;\n}\n\nstatic stbtt__buf stbtt__get_subrs(stbtt__buf cff, stbtt__buf fontdict)\n{\n   stbtt_uint32 subrsoff = 0, private_loc[2] = { 0, 0 };\n   stbtt__buf pdict;\n   stbtt__dict_get_ints(&fontdict, 18, 2, private_loc);\n   if (!private_loc[1] || !private_loc[0]) return stbtt__new_buf(NULL, 0);\n   pdict = stbtt__buf_range(&cff, private_loc[1], private_loc[0]);\n   stbtt__dict_get_ints(&pdict, 19, 1, &subrsoff);\n   if (!subrsoff) return stbtt__new_buf(NULL, 0);\n   stbtt__buf_seek(&cff, private_loc[1]+subrsoff);\n   return stbtt__cff_get_index(&cff);\n}\n\n// since most people won't use this, find this table the first time it's needed\nstatic int stbtt__get_svg(stbtt_fontinfo *info)\n{\n   stbtt_uint32 t;\n   if (info->svg < 0) {\n      t = stbtt__find_table(info->data, info->fontstart, \"SVG \");\n      if (t) {\n         stbtt_uint32 offset = ttULONG(info->data + t + 2);\n         info->svg = t + offset;\n      } else {\n         info->svg = 0;\n      }\n   }\n   return info->svg;\n}\n\nstatic int stbtt_InitFont_internal(stbtt_fontinfo *info, unsigned char *data, int fontstart)\n{\n   stbtt_uint32 cmap, t;\n   stbtt_int32 i,numTables;\n\n   info->data = data;\n   info->fontstart = fontstart;\n   info->cff = stbtt__new_buf(NULL, 0);\n\n   cmap = stbtt__find_table(data, fontstart, \"cmap\");       // required\n   info->loca = stbtt__find_table(data, fontstart, \"loca\"); // required\n   info->head = stbtt__find_table(data, fontstart, \"head\"); // required\n   info->glyf = stbtt__find_table(data, fontstart, \"glyf\"); // required\n   info->hhea = stbtt__find_table(data, fontstart, \"hhea\"); // required\n   info->hmtx = stbtt__find_table(data, fontstart, \"hmtx\"); // required\n   info->kern = stbtt__find_table(data, fontstart, \"kern\"); // not required\n   info->gpos = stbtt__find_table(data, fontstart, \"GPOS\"); // not required\n\n   if (!cmap || !info->head || !info->hhea || !info->hmtx)\n      return 0;\n   if (info->glyf) {\n      // required for truetype\n      if (!info->loca) return 0;\n   } else {\n      // initialization for CFF / Type2 fonts (OTF)\n      stbtt__buf b, topdict, topdictidx;\n      stbtt_uint32 cstype = 2, charstrings = 0, fdarrayoff = 0, fdselectoff = 0;\n      stbtt_uint32 cff;\n\n      cff = stbtt__find_table(data, fontstart, \"CFF \");\n      if (!cff) return 0;\n\n      info->fontdicts = stbtt__new_buf(NULL, 0);\n      info->fdselect = stbtt__new_buf(NULL, 0);\n\n      // @TODO this should use size from table (not 512MB)\n      info->cff = stbtt__new_buf(data+cff, 512*1024*1024);\n      b = info->cff;\n\n      // read the header\n      stbtt__buf_skip(&b, 2);\n      stbtt__buf_seek(&b, stbtt__buf_get8(&b)); // hdrsize\n\n      // @TODO the name INDEX could list multiple fonts,\n      // but we just use the first one.\n      stbtt__cff_get_index(&b);  // name INDEX\n      topdictidx = stbtt__cff_get_index(&b);\n      topdict = stbtt__cff_index_get(topdictidx, 0);\n      stbtt__cff_get_index(&b);  // string INDEX\n      info->gsubrs = stbtt__cff_get_index(&b);\n\n      stbtt__dict_get_ints(&topdict, 17, 1, &charstrings);\n      stbtt__dict_get_ints(&topdict, 0x100 | 6, 1, &cstype);\n      stbtt__dict_get_ints(&topdict, 0x100 | 36, 1, &fdarrayoff);\n      stbtt__dict_get_ints(&topdict, 0x100 | 37, 1, &fdselectoff);\n      info->subrs = stbtt__get_subrs(b, topdict);\n\n      // we only support Type 2 charstrings\n      if (cstype != 2) return 0;\n      if (charstrings == 0) return 0;\n\n      if (fdarrayoff) {\n         // looks like a CID font\n         if (!fdselectoff) return 0;\n         stbtt__buf_seek(&b, fdarrayoff);\n         info->fontdicts = stbtt__cff_get_index(&b);\n         info->fdselect = stbtt__buf_range(&b, fdselectoff, b.size-fdselectoff);\n      }\n\n      stbtt__buf_seek(&b, charstrings);\n      info->charstrings = stbtt__cff_get_index(&b);\n   }\n\n   t = stbtt__find_table(data, fontstart, \"maxp\");\n   if (t)\n      info->numGlyphs = ttUSHORT(data+t+4);\n   else\n      info->numGlyphs = 0xffff;\n\n   info->svg = -1;\n\n   // find a cmap encoding table we understand *now* to avoid searching\n   // later. (todo: could make this installable)\n   // the same regardless of glyph.\n   numTables = ttUSHORT(data + cmap + 2);\n   info->index_map = 0;\n   for (i=0; i < numTables; ++i) {\n      stbtt_uint32 encoding_record = cmap + 4 + 8 * i;\n      // find an encoding we understand:\n      switch(ttUSHORT(data+encoding_record)) {\n         case STBTT_PLATFORM_ID_MICROSOFT:\n            switch (ttUSHORT(data+encoding_record+2)) {\n               case STBTT_MS_EID_UNICODE_BMP:\n               case STBTT_MS_EID_UNICODE_FULL:\n                  // MS/Unicode\n                  info->index_map = cmap + ttULONG(data+encoding_record+4);\n                  break;\n            }\n            break;\n        case STBTT_PLATFORM_ID_UNICODE:\n            // Mac/iOS has these\n            // all the encodingIDs are unicode, so we don't bother to check it\n            info->index_map = cmap + ttULONG(data+encoding_record+4);\n            break;\n      }\n   }\n   if (info->index_map == 0)\n      return 0;\n\n   info->indexToLocFormat = ttUSHORT(data+info->head + 50);\n   return 1;\n}\n\nSTBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codepoint)\n{\n   stbtt_uint8 *data = info->data;\n   stbtt_uint32 index_map = info->index_map;\n\n   stbtt_uint16 format = ttUSHORT(data + index_map + 0);\n   if (format == 0) { // apple byte encoding\n      stbtt_int32 bytes = ttUSHORT(data + index_map + 2);\n      if (unicode_codepoint < bytes-6)\n         return ttBYTE(data + index_map + 6 + unicode_codepoint);\n      return 0;\n   } else if (format == 6) {\n      stbtt_uint32 first = ttUSHORT(data + index_map + 6);\n      stbtt_uint32 count = ttUSHORT(data + index_map + 8);\n      if ((stbtt_uint32) unicode_codepoint >= first && (stbtt_uint32) unicode_codepoint < first+count)\n         return ttUSHORT(data + index_map + 10 + (unicode_codepoint - first)*2);\n      return 0;\n   } else if (format == 2) {\n      STBTT_assert(0); // @TODO: high-byte mapping for japanese/chinese/korean\n      return 0;\n   } else if (format == 4) { // standard mapping for windows fonts: binary search collection of ranges\n      stbtt_uint16 segcount = ttUSHORT(data+index_map+6) >> 1;\n      stbtt_uint16 searchRange = ttUSHORT(data+index_map+8) >> 1;\n      stbtt_uint16 entrySelector = ttUSHORT(data+index_map+10);\n      stbtt_uint16 rangeShift = ttUSHORT(data+index_map+12) >> 1;\n\n      // do a binary search of the segments\n      stbtt_uint32 endCount = index_map + 14;\n      stbtt_uint32 search = endCount;\n\n      if (unicode_codepoint > 0xffff)\n         return 0;\n\n      // they lie from endCount .. endCount + segCount\n      // but searchRange is the nearest power of two, so...\n      if (unicode_codepoint >= ttUSHORT(data + search + rangeShift*2))\n         search += rangeShift*2;\n\n      // now decrement to bias correctly to find smallest\n      search -= 2;\n      while (entrySelector) {\n         stbtt_uint16 end;\n         searchRange >>= 1;\n         end = ttUSHORT(data + search + searchRange*2);\n         if (unicode_codepoint > end)\n            search += searchRange*2;\n         --entrySelector;\n      }\n      search += 2;\n\n      {\n         stbtt_uint16 offset, start, last;\n         stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);\n\n         start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);\n         last = ttUSHORT(data + endCount + 2*item);\n         if (unicode_codepoint < start || unicode_codepoint > last)\n            return 0;\n\n         offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);\n         if (offset == 0)\n            return (stbtt_uint16) (unicode_codepoint + ttSHORT(data + index_map + 14 + segcount*4 + 2 + 2*item));\n\n         return ttUSHORT(data + offset + (unicode_codepoint-start)*2 + index_map + 14 + segcount*6 + 2 + 2*item);\n      }\n   } else if (format == 12 || format == 13) {\n      stbtt_uint32 ngroups = ttULONG(data+index_map+12);\n      stbtt_int32 low,high;\n      low = 0; high = (stbtt_int32)ngroups;\n      // Binary search the right group.\n      while (low < high) {\n         stbtt_int32 mid = low + ((high-low) >> 1); // rounds down, so low <= mid < high\n         stbtt_uint32 start_char = ttULONG(data+index_map+16+mid*12);\n         stbtt_uint32 end_char = ttULONG(data+index_map+16+mid*12+4);\n         if ((stbtt_uint32) unicode_codepoint < start_char)\n            high = mid;\n         else if ((stbtt_uint32) unicode_codepoint > end_char)\n            low = mid+1;\n         else {\n            stbtt_uint32 start_glyph = ttULONG(data+index_map+16+mid*12+8);\n            if (format == 12)\n               return start_glyph + unicode_codepoint-start_char;\n            else // format == 13\n               return start_glyph;\n         }\n      }\n      return 0; // not found\n   }\n   // @TODO\n   STBTT_assert(0);\n   return 0;\n}\n\nSTBTT_DEF int stbtt_GetCodepointShape(const stbtt_fontinfo *info, int unicode_codepoint, stbtt_vertex **vertices)\n{\n   return stbtt_GetGlyphShape(info, stbtt_FindGlyphIndex(info, unicode_codepoint), vertices);\n}\n\nstatic void stbtt_setvertex(stbtt_vertex *v, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy)\n{\n   v->type = type;\n   v->x = (stbtt_int16) x;\n   v->y = (stbtt_int16) y;\n   v->cx = (stbtt_int16) cx;\n   v->cy = (stbtt_int16) cy;\n}\n\nstatic int stbtt__GetGlyfOffset(const stbtt_fontinfo *info, int glyph_index)\n{\n   int g1,g2;\n\n   STBTT_assert(!info->cff.size);\n\n   if (glyph_index >= info->numGlyphs) return -1; // glyph index out of range\n   if (info->indexToLocFormat >= 2)    return -1; // unknown index->glyph map format\n\n   if (info->indexToLocFormat == 0) {\n      g1 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2) * 2;\n      g2 = info->glyf + ttUSHORT(info->data + info->loca + glyph_index * 2 + 2) * 2;\n   } else {\n      g1 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4);\n      g2 = info->glyf + ttULONG (info->data + info->loca + glyph_index * 4 + 4);\n   }\n\n   return g1==g2 ? -1 : g1; // if length is 0, return -1\n}\n\nstatic int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1);\n\nSTBTT_DEF int stbtt_GetGlyphBox(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)\n{\n   if (info->cff.size) {\n      stbtt__GetGlyphInfoT2(info, glyph_index, x0, y0, x1, y1);\n   } else {\n      int g = stbtt__GetGlyfOffset(info, glyph_index);\n      if (g < 0) return 0;\n\n      if (x0) *x0 = ttSHORT(info->data + g + 2);\n      if (y0) *y0 = ttSHORT(info->data + g + 4);\n      if (x1) *x1 = ttSHORT(info->data + g + 6);\n      if (y1) *y1 = ttSHORT(info->data + g + 8);\n   }\n   return 1;\n}\n\nSTBTT_DEF int stbtt_GetCodepointBox(const stbtt_fontinfo *info, int codepoint, int *x0, int *y0, int *x1, int *y1)\n{\n   return stbtt_GetGlyphBox(info, stbtt_FindGlyphIndex(info,codepoint), x0,y0,x1,y1);\n}\n\nSTBTT_DEF int stbtt_IsGlyphEmpty(const stbtt_fontinfo *info, int glyph_index)\n{\n   stbtt_int16 numberOfContours;\n   int g;\n   if (info->cff.size)\n      return stbtt__GetGlyphInfoT2(info, glyph_index, NULL, NULL, NULL, NULL) == 0;\n   g = stbtt__GetGlyfOffset(info, glyph_index);\n   if (g < 0) return 1;\n   numberOfContours = ttSHORT(info->data + g);\n   return numberOfContours == 0;\n}\n\nstatic int stbtt__close_shape(stbtt_vertex *vertices, int num_vertices, int was_off, int start_off,\n    stbtt_int32 sx, stbtt_int32 sy, stbtt_int32 scx, stbtt_int32 scy, stbtt_int32 cx, stbtt_int32 cy)\n{\n   if (start_off) {\n      if (was_off)\n         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+scx)>>1, (cy+scy)>>1, cx,cy);\n      stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, sx,sy,scx,scy);\n   } else {\n      if (was_off)\n         stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve,sx,sy,cx,cy);\n      else\n         stbtt_setvertex(&vertices[num_vertices++], STBTT_vline,sx,sy,0,0);\n   }\n   return num_vertices;\n}\n\nstatic int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)\n{\n   stbtt_int16 numberOfContours;\n   stbtt_uint8 *endPtsOfContours;\n   stbtt_uint8 *data = info->data;\n   stbtt_vertex *vertices=0;\n   int num_vertices=0;\n   int g = stbtt__GetGlyfOffset(info, glyph_index);\n\n   *pvertices = NULL;\n\n   if (g < 0) return 0;\n\n   numberOfContours = ttSHORT(data + g);\n\n   if (numberOfContours > 0) {\n      stbtt_uint8 flags=0,flagcount;\n      stbtt_int32 ins, i,j=0,m,n, next_move, was_off=0, off, start_off=0;\n      stbtt_int32 x,y,cx,cy,sx,sy, scx,scy;\n      stbtt_uint8 *points;\n      endPtsOfContours = (data + g + 10);\n      ins = ttUSHORT(data + g + 10 + numberOfContours * 2);\n      points = data + g + 10 + numberOfContours * 2 + 2 + ins;\n\n      n = 1+ttUSHORT(endPtsOfContours + numberOfContours*2-2);\n\n      m = n + 2*numberOfContours;  // a loose bound on how many vertices we might need\n      vertices = (stbtt_vertex *) STBTT_malloc(m * sizeof(vertices[0]), info->userdata);\n      if (vertices == 0)\n         return 0;\n\n      next_move = 0;\n      flagcount=0;\n\n      // in first pass, we load uninterpreted data into the allocated array\n      // above, shifted to the end of the array so we won't overwrite it when\n      // we create our final data starting from the front\n\n      off = m - n; // starting offset for uninterpreted data, regardless of how m ends up being calculated\n\n      // first load flags\n\n      for (i=0; i < n; ++i) {\n         if (flagcount == 0) {\n            flags = *points++;\n            if (flags & 8)\n               flagcount = *points++;\n         } else\n            --flagcount;\n         vertices[off+i].type = flags;\n      }\n\n      // now load x coordinates\n      x=0;\n      for (i=0; i < n; ++i) {\n         flags = vertices[off+i].type;\n         if (flags & 2) {\n            stbtt_int16 dx = *points++;\n            x += (flags & 16) ? dx : -dx; // ???\n         } else {\n            if (!(flags & 16)) {\n               x = x + (stbtt_int16) (points[0]*256 + points[1]);\n               points += 2;\n            }\n         }\n         vertices[off+i].x = (stbtt_int16) x;\n      }\n\n      // now load y coordinates\n      y=0;\n      for (i=0; i < n; ++i) {\n         flags = vertices[off+i].type;\n         if (flags & 4) {\n            stbtt_int16 dy = *points++;\n            y += (flags & 32) ? dy : -dy; // ???\n         } else {\n            if (!(flags & 32)) {\n               y = y + (stbtt_int16) (points[0]*256 + points[1]);\n               points += 2;\n            }\n         }\n         vertices[off+i].y = (stbtt_int16) y;\n      }\n\n      // now convert them to our format\n      num_vertices=0;\n      sx = sy = cx = cy = scx = scy = 0;\n      for (i=0; i < n; ++i) {\n         flags = vertices[off+i].type;\n         x     = (stbtt_int16) vertices[off+i].x;\n         y     = (stbtt_int16) vertices[off+i].y;\n\n         if (next_move == i) {\n            if (i != 0)\n               num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);\n\n            // now start the new one\n            start_off = !(flags & 1);\n            if (start_off) {\n               // if we start off with an off-curve point, then when we need to find a point on the curve\n               // where we can start, and we need to save some state for when we wraparound.\n               scx = x;\n               scy = y;\n               if (!(vertices[off+i+1].type & 1)) {\n                  // next point is also a curve point, so interpolate an on-point curve\n                  sx = (x + (stbtt_int32) vertices[off+i+1].x) >> 1;\n                  sy = (y + (stbtt_int32) vertices[off+i+1].y) >> 1;\n               } else {\n                  // otherwise just use the next point as our start point\n                  sx = (stbtt_int32) vertices[off+i+1].x;\n                  sy = (stbtt_int32) vertices[off+i+1].y;\n                  ++i; // we're using point i+1 as the starting point, so skip it\n               }\n            } else {\n               sx = x;\n               sy = y;\n            }\n            stbtt_setvertex(&vertices[num_vertices++], STBTT_vmove,sx,sy,0,0);\n            was_off = 0;\n            next_move = 1 + ttUSHORT(endPtsOfContours+j*2);\n            ++j;\n         } else {\n            if (!(flags & 1)) { // if it's a curve\n               if (was_off) // two off-curve control points in a row means interpolate an on-curve midpoint\n                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, (cx+x)>>1, (cy+y)>>1, cx, cy);\n               cx = x;\n               cy = y;\n               was_off = 1;\n            } else {\n               if (was_off)\n                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vcurve, x,y, cx, cy);\n               else\n                  stbtt_setvertex(&vertices[num_vertices++], STBTT_vline, x,y,0,0);\n               was_off = 0;\n            }\n         }\n      }\n      num_vertices = stbtt__close_shape(vertices, num_vertices, was_off, start_off, sx,sy,scx,scy,cx,cy);\n   } else if (numberOfContours < 0) {\n      // Compound shapes.\n      int more = 1;\n      stbtt_uint8 *comp = data + g + 10;\n      num_vertices = 0;\n      vertices = 0;\n      while (more) {\n         stbtt_uint16 flags, gidx;\n         int comp_num_verts = 0, i;\n         stbtt_vertex *comp_verts = 0, *tmp = 0;\n         float mtx[6] = {1,0,0,1,0,0}, m, n;\n\n         flags = ttSHORT(comp); comp+=2;\n         gidx = ttSHORT(comp); comp+=2;\n\n         if (flags & 2) { // XY values\n            if (flags & 1) { // shorts\n               mtx[4] = ttSHORT(comp); comp+=2;\n               mtx[5] = ttSHORT(comp); comp+=2;\n            } else {\n               mtx[4] = ttCHAR(comp); comp+=1;\n               mtx[5] = ttCHAR(comp); comp+=1;\n            }\n         }\n         else {\n            // @TODO handle matching point\n            STBTT_assert(0);\n         }\n         if (flags & (1<<3)) { // WE_HAVE_A_SCALE\n            mtx[0] = mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[1] = mtx[2] = 0;\n         } else if (flags & (1<<6)) { // WE_HAVE_AN_X_AND_YSCALE\n            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[1] = mtx[2] = 0;\n            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;\n         } else if (flags & (1<<7)) { // WE_HAVE_A_TWO_BY_TWO\n            mtx[0] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[1] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[2] = ttSHORT(comp)/16384.0f; comp+=2;\n            mtx[3] = ttSHORT(comp)/16384.0f; comp+=2;\n         }\n\n         // Find transformation scales.\n         m = (float) STBTT_sqrt(mtx[0]*mtx[0] + mtx[1]*mtx[1]);\n         n = (float) STBTT_sqrt(mtx[2]*mtx[2] + mtx[3]*mtx[3]);\n\n         // Get indexed glyph.\n         comp_num_verts = stbtt_GetGlyphShape(info, gidx, &comp_verts);\n         if (comp_num_verts > 0) {\n            // Transform vertices.\n            for (i = 0; i < comp_num_verts; ++i) {\n               stbtt_vertex* v = &comp_verts[i];\n               stbtt_vertex_type x,y;\n               x=v->x; y=v->y;\n               v->x = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));\n               v->y = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));\n               x=v->cx; y=v->cy;\n               v->cx = (stbtt_vertex_type)(m * (mtx[0]*x + mtx[2]*y + mtx[4]));\n               v->cy = (stbtt_vertex_type)(n * (mtx[1]*x + mtx[3]*y + mtx[5]));\n            }\n            // Append vertices.\n            tmp = (stbtt_vertex*)STBTT_malloc((num_vertices+comp_num_verts)*sizeof(stbtt_vertex), info->userdata);\n            if (!tmp) {\n               if (vertices) STBTT_free(vertices, info->userdata);\n               if (comp_verts) STBTT_free(comp_verts, info->userdata);\n               return 0;\n            }\n            if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));\n            STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));\n            if (vertices) STBTT_free(vertices, info->userdata);\n            vertices = tmp;\n            STBTT_free(comp_verts, info->userdata);\n            num_vertices += comp_num_verts;\n         }\n         // More components ?\n         more = flags & (1<<5);\n      }\n   } else {\n      // numberOfCounters == 0, do nothing\n   }\n\n   *pvertices = vertices;\n   return num_vertices;\n}\n\ntypedef struct\n{\n   int bounds;\n   int started;\n   float first_x, first_y;\n   float x, y;\n   stbtt_int32 min_x, max_x, min_y, max_y;\n\n   stbtt_vertex *pvertices;\n   int num_vertices;\n} stbtt__csctx;\n\n#define STBTT__CSCTX_INIT(bounds) {bounds,0, 0,0, 0,0, 0,0,0,0, NULL, 0}\n\nstatic void stbtt__track_vertex(stbtt__csctx *c, stbtt_int32 x, stbtt_int32 y)\n{\n   if (x > c->max_x || !c->started) c->max_x = x;\n   if (y > c->max_y || !c->started) c->max_y = y;\n   if (x < c->min_x || !c->started) c->min_x = x;\n   if (y < c->min_y || !c->started) c->min_y = y;\n   c->started = 1;\n}\n\nstatic void stbtt__csctx_v(stbtt__csctx *c, stbtt_uint8 type, stbtt_int32 x, stbtt_int32 y, stbtt_int32 cx, stbtt_int32 cy, stbtt_int32 cx1, stbtt_int32 cy1)\n{\n   if (c->bounds) {\n      stbtt__track_vertex(c, x, y);\n      if (type == STBTT_vcubic) {\n         stbtt__track_vertex(c, cx, cy);\n         stbtt__track_vertex(c, cx1, cy1);\n      }\n   } else {\n      stbtt_setvertex(&c->pvertices[c->num_vertices], type, x, y, cx, cy);\n      c->pvertices[c->num_vertices].cx1 = (stbtt_int16) cx1;\n      c->pvertices[c->num_vertices].cy1 = (stbtt_int16) cy1;\n   }\n   c->num_vertices++;\n}\n\nstatic void stbtt__csctx_close_shape(stbtt__csctx *ctx)\n{\n   if (ctx->first_x != ctx->x || ctx->first_y != ctx->y)\n      stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->first_x, (int)ctx->first_y, 0, 0, 0, 0);\n}\n\nstatic void stbtt__csctx_rmove_to(stbtt__csctx *ctx, float dx, float dy)\n{\n   stbtt__csctx_close_shape(ctx);\n   ctx->first_x = ctx->x = ctx->x + dx;\n   ctx->first_y = ctx->y = ctx->y + dy;\n   stbtt__csctx_v(ctx, STBTT_vmove, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);\n}\n\nstatic void stbtt__csctx_rline_to(stbtt__csctx *ctx, float dx, float dy)\n{\n   ctx->x += dx;\n   ctx->y += dy;\n   stbtt__csctx_v(ctx, STBTT_vline, (int)ctx->x, (int)ctx->y, 0, 0, 0, 0);\n}\n\nstatic void stbtt__csctx_rccurve_to(stbtt__csctx *ctx, float dx1, float dy1, float dx2, float dy2, float dx3, float dy3)\n{\n   float cx1 = ctx->x + dx1;\n   float cy1 = ctx->y + dy1;\n   float cx2 = cx1 + dx2;\n   float cy2 = cy1 + dy2;\n   ctx->x = cx2 + dx3;\n   ctx->y = cy2 + dy3;\n   stbtt__csctx_v(ctx, STBTT_vcubic, (int)ctx->x, (int)ctx->y, (int)cx1, (int)cy1, (int)cx2, (int)cy2);\n}\n\nstatic stbtt__buf stbtt__get_subr(stbtt__buf idx, int n)\n{\n   int count = stbtt__cff_index_count(&idx);\n   int bias = 107;\n   if (count >= 33900)\n      bias = 32768;\n   else if (count >= 1240)\n      bias = 1131;\n   n += bias;\n   if (n < 0 || n >= count)\n      return stbtt__new_buf(NULL, 0);\n   return stbtt__cff_index_get(idx, n);\n}\n\nstatic stbtt__buf stbtt__cid_get_glyph_subrs(const stbtt_fontinfo *info, int glyph_index)\n{\n   stbtt__buf fdselect = info->fdselect;\n   int nranges, start, end, v, fmt, fdselector = -1, i;\n\n   stbtt__buf_seek(&fdselect, 0);\n   fmt = stbtt__buf_get8(&fdselect);\n   if (fmt == 0) {\n      // untested\n      stbtt__buf_skip(&fdselect, glyph_index);\n      fdselector = stbtt__buf_get8(&fdselect);\n   } else if (fmt == 3) {\n      nranges = stbtt__buf_get16(&fdselect);\n      start = stbtt__buf_get16(&fdselect);\n      for (i = 0; i < nranges; i++) {\n         v = stbtt__buf_get8(&fdselect);\n         end = stbtt__buf_get16(&fdselect);\n         if (glyph_index >= start && glyph_index < end) {\n            fdselector = v;\n            break;\n         }\n         start = end;\n      }\n   }\n   if (fdselector == -1) stbtt__new_buf(NULL, 0);\n   return stbtt__get_subrs(info->cff, stbtt__cff_index_get(info->fontdicts, fdselector));\n}\n\nstatic int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, stbtt__csctx *c)\n{\n   int in_header = 1, maskbits = 0, subr_stack_height = 0, sp = 0, v, i, b0;\n   int has_subrs = 0, clear_stack;\n   float s[48];\n   stbtt__buf subr_stack[10], subrs = info->subrs, b;\n   float f;\n\n#define STBTT__CSERR(s) (0)\n\n   // this currently ignores the initial width value, which isn't needed if we have hmtx\n   b = stbtt__cff_index_get(info->charstrings, glyph_index);\n   while (b.cursor < b.size) {\n      i = 0;\n      clear_stack = 1;\n      b0 = stbtt__buf_get8(&b);\n      switch (b0) {\n      // @TODO implement hinting\n      case 0x13: // hintmask\n      case 0x14: // cntrmask\n         if (in_header)\n            maskbits += (sp / 2); // implicit \"vstem\"\n         in_header = 0;\n         stbtt__buf_skip(&b, (maskbits + 7) / 8);\n         break;\n\n      case 0x01: // hstem\n      case 0x03: // vstem\n      case 0x12: // hstemhm\n      case 0x17: // vstemhm\n         maskbits += (sp / 2);\n         break;\n\n      case 0x15: // rmoveto\n         in_header = 0;\n         if (sp < 2) return STBTT__CSERR(\"rmoveto stack\");\n         stbtt__csctx_rmove_to(c, s[sp-2], s[sp-1]);\n         break;\n      case 0x04: // vmoveto\n         in_header = 0;\n         if (sp < 1) return STBTT__CSERR(\"vmoveto stack\");\n         stbtt__csctx_rmove_to(c, 0, s[sp-1]);\n         break;\n      case 0x16: // hmoveto\n         in_header = 0;\n         if (sp < 1) return STBTT__CSERR(\"hmoveto stack\");\n         stbtt__csctx_rmove_to(c, s[sp-1], 0);\n         break;\n\n      case 0x05: // rlineto\n         if (sp < 2) return STBTT__CSERR(\"rlineto stack\");\n         for (; i + 1 < sp; i += 2)\n            stbtt__csctx_rline_to(c, s[i], s[i+1]);\n         break;\n\n      // hlineto/vlineto and vhcurveto/hvcurveto alternate horizontal and vertical\n      // starting from a different place.\n\n      case 0x07: // vlineto\n         if (sp < 1) return STBTT__CSERR(\"vlineto stack\");\n         goto vlineto;\n      case 0x06: // hlineto\n         if (sp < 1) return STBTT__CSERR(\"hlineto stack\");\n         for (;;) {\n            if (i >= sp) break;\n            stbtt__csctx_rline_to(c, s[i], 0);\n            i++;\n      vlineto:\n            if (i >= sp) break;\n            stbtt__csctx_rline_to(c, 0, s[i]);\n            i++;\n         }\n         break;\n\n      case 0x1F: // hvcurveto\n         if (sp < 4) return STBTT__CSERR(\"hvcurveto stack\");\n         goto hvcurveto;\n      case 0x1E: // vhcurveto\n         if (sp < 4) return STBTT__CSERR(\"vhcurveto stack\");\n         for (;;) {\n            if (i + 3 >= sp) break;\n            stbtt__csctx_rccurve_to(c, 0, s[i], s[i+1], s[i+2], s[i+3], (sp - i == 5) ? s[i + 4] : 0.0f);\n            i += 4;\n      hvcurveto:\n            if (i + 3 >= sp) break;\n            stbtt__csctx_rccurve_to(c, s[i], 0, s[i+1], s[i+2], (sp - i == 5) ? s[i+4] : 0.0f, s[i+3]);\n            i += 4;\n         }\n         break;\n\n      case 0x08: // rrcurveto\n         if (sp < 6) return STBTT__CSERR(\"rcurveline stack\");\n         for (; i + 5 < sp; i += 6)\n            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);\n         break;\n\n      case 0x18: // rcurveline\n         if (sp < 8) return STBTT__CSERR(\"rcurveline stack\");\n         for (; i + 5 < sp - 2; i += 6)\n            stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);\n         if (i + 1 >= sp) return STBTT__CSERR(\"rcurveline stack\");\n         stbtt__csctx_rline_to(c, s[i], s[i+1]);\n         break;\n\n      case 0x19: // rlinecurve\n         if (sp < 8) return STBTT__CSERR(\"rlinecurve stack\");\n         for (; i + 1 < sp - 6; i += 2)\n            stbtt__csctx_rline_to(c, s[i], s[i+1]);\n         if (i + 5 >= sp) return STBTT__CSERR(\"rlinecurve stack\");\n         stbtt__csctx_rccurve_to(c, s[i], s[i+1], s[i+2], s[i+3], s[i+4], s[i+5]);\n         break;\n\n      case 0x1A: // vvcurveto\n      case 0x1B: // hhcurveto\n         if (sp < 4) return STBTT__CSERR(\"(vv|hh)curveto stack\");\n         f = 0.0;\n         if (sp & 1) { f = s[i]; i++; }\n         for (; i + 3 < sp; i += 4) {\n            if (b0 == 0x1B)\n               stbtt__csctx_rccurve_to(c, s[i], f, s[i+1], s[i+2], s[i+3], 0.0);\n            else\n               stbtt__csctx_rccurve_to(c, f, s[i], s[i+1], s[i+2], 0.0, s[i+3]);\n            f = 0.0;\n         }\n         break;\n\n      case 0x0A: // callsubr\n         if (!has_subrs) {\n            if (info->fdselect.size)\n               subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);\n            has_subrs = 1;\n         }\n         // FALLTHROUGH\n      case 0x1D: // callgsubr\n         if (sp < 1) return STBTT__CSERR(\"call(g|)subr stack\");\n         v = (int) s[--sp];\n         if (subr_stack_height >= 10) return STBTT__CSERR(\"recursion limit\");\n         subr_stack[subr_stack_height++] = b;\n         b = stbtt__get_subr(b0 == 0x0A ? subrs : info->gsubrs, v);\n         if (b.size == 0) return STBTT__CSERR(\"subr not found\");\n         b.cursor = 0;\n         clear_stack = 0;\n         break;\n\n      case 0x0B: // return\n         if (subr_stack_height <= 0) return STBTT__CSERR(\"return outside subr\");\n         b = subr_stack[--subr_stack_height];\n         clear_stack = 0;\n         break;\n\n      case 0x0E: // endchar\n         stbtt__csctx_close_shape(c);\n         return 1;\n\n      case 0x0C: { // two-byte escape\n         float dx1, dx2, dx3, dx4, dx5, dx6, dy1, dy2, dy3, dy4, dy5, dy6;\n         float dx, dy;\n         int b1 = stbtt__buf_get8(&b);\n         switch (b1) {\n         // @TODO These \"flex\" implementations ignore the flex-depth and resolution,\n         // and always draw beziers.\n         case 0x22: // hflex\n            if (sp < 7) return STBTT__CSERR(\"hflex stack\");\n            dx1 = s[0];\n            dx2 = s[1];\n            dy2 = s[2];\n            dx3 = s[3];\n            dx4 = s[4];\n            dx5 = s[5];\n            dx6 = s[6];\n            stbtt__csctx_rccurve_to(c, dx1, 0, dx2, dy2, dx3, 0);\n            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, -dy2, dx6, 0);\n            break;\n\n         case 0x23: // flex\n            if (sp < 13) return STBTT__CSERR(\"flex stack\");\n            dx1 = s[0];\n            dy1 = s[1];\n            dx2 = s[2];\n            dy2 = s[3];\n            dx3 = s[4];\n            dy3 = s[5];\n            dx4 = s[6];\n            dy4 = s[7];\n            dx5 = s[8];\n            dy5 = s[9];\n            dx6 = s[10];\n            dy6 = s[11];\n            //fd is s[12]\n            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);\n            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);\n            break;\n\n         case 0x24: // hflex1\n            if (sp < 9) return STBTT__CSERR(\"hflex1 stack\");\n            dx1 = s[0];\n            dy1 = s[1];\n            dx2 = s[2];\n            dy2 = s[3];\n            dx3 = s[4];\n            dx4 = s[5];\n            dx5 = s[6];\n            dy5 = s[7];\n            dx6 = s[8];\n            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, 0);\n            stbtt__csctx_rccurve_to(c, dx4, 0, dx5, dy5, dx6, -(dy1+dy2+dy5));\n            break;\n\n         case 0x25: // flex1\n            if (sp < 11) return STBTT__CSERR(\"flex1 stack\");\n            dx1 = s[0];\n            dy1 = s[1];\n            dx2 = s[2];\n            dy2 = s[3];\n            dx3 = s[4];\n            dy3 = s[5];\n            dx4 = s[6];\n            dy4 = s[7];\n            dx5 = s[8];\n            dy5 = s[9];\n            dx6 = dy6 = s[10];\n            dx = dx1+dx2+dx3+dx4+dx5;\n            dy = dy1+dy2+dy3+dy4+dy5;\n            if (STBTT_fabs(dx) > STBTT_fabs(dy))\n               dy6 = -dy;\n            else\n               dx6 = -dx;\n            stbtt__csctx_rccurve_to(c, dx1, dy1, dx2, dy2, dx3, dy3);\n            stbtt__csctx_rccurve_to(c, dx4, dy4, dx5, dy5, dx6, dy6);\n            break;\n\n         default:\n            return STBTT__CSERR(\"unimplemented\");\n         }\n      } break;\n\n      default:\n         if (b0 != 255 && b0 != 28 && b0 < 32)\n            return STBTT__CSERR(\"reserved operator\");\n\n         // push immediate\n         if (b0 == 255) {\n            f = (float)(stbtt_int32)stbtt__buf_get32(&b) / 0x10000;\n         } else {\n            stbtt__buf_skip(&b, -1);\n            f = (float)(stbtt_int16)stbtt__cff_int(&b);\n         }\n         if (sp >= 48) return STBTT__CSERR(\"push stack overflow\");\n         s[sp++] = f;\n         clear_stack = 0;\n         break;\n      }\n      if (clear_stack) sp = 0;\n   }\n   return STBTT__CSERR(\"no endchar\");\n\n#undef STBTT__CSERR\n}\n\nstatic int stbtt__GetGlyphShapeT2(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)\n{\n   // runs the charstring twice, once to count and once to output (to avoid realloc)\n   stbtt__csctx count_ctx = STBTT__CSCTX_INIT(1);\n   stbtt__csctx output_ctx = STBTT__CSCTX_INIT(0);\n   if (stbtt__run_charstring(info, glyph_index, &count_ctx)) {\n      *pvertices = (stbtt_vertex*)STBTT_malloc(count_ctx.num_vertices*sizeof(stbtt_vertex), info->userdata);\n      output_ctx.pvertices = *pvertices;\n      if (stbtt__run_charstring(info, glyph_index, &output_ctx)) {\n         STBTT_assert(output_ctx.num_vertices == count_ctx.num_vertices);\n         return output_ctx.num_vertices;\n      }\n   }\n   *pvertices = NULL;\n   return 0;\n}\n\nstatic int stbtt__GetGlyphInfoT2(const stbtt_fontinfo *info, int glyph_index, int *x0, int *y0, int *x1, int *y1)\n{\n   stbtt__csctx c = STBTT__CSCTX_INIT(1);\n   int r = stbtt__run_charstring(info, glyph_index, &c);\n   if (x0)  *x0 = r ? c.min_x : 0;\n   if (y0)  *y0 = r ? c.min_y : 0;\n   if (x1)  *x1 = r ? c.max_x : 0;\n   if (y1)  *y1 = r ? c.max_y : 0;\n   return r ? c.num_vertices : 0;\n}\n\nSTBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, stbtt_vertex **pvertices)\n{\n   if (!info->cff.size)\n      return stbtt__GetGlyphShapeTT(info, glyph_index, pvertices);\n   else\n      return stbtt__GetGlyphShapeT2(info, glyph_index, pvertices);\n}\n\nSTBTT_DEF void stbtt_GetGlyphHMetrics(const stbtt_fontinfo *info, int glyph_index, int *advanceWidth, int *leftSideBearing)\n{\n   stbtt_uint16 numOfLongHorMetrics = ttUSHORT(info->data+info->hhea + 34);\n   if (glyph_index < numOfLongHorMetrics) {\n      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*glyph_index);\n      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*glyph_index + 2);\n   } else {\n      if (advanceWidth)     *advanceWidth    = ttSHORT(info->data + info->hmtx + 4*(numOfLongHorMetrics-1));\n      if (leftSideBearing)  *leftSideBearing = ttSHORT(info->data + info->hmtx + 4*numOfLongHorMetrics + 2*(glyph_index - numOfLongHorMetrics));\n   }\n}\n\nSTBTT_DEF int  stbtt_GetKerningTableLength(const stbtt_fontinfo *info)\n{\n   stbtt_uint8 *data = info->data + info->kern;\n\n   // we only look at the first table. it must be 'horizontal' and format 0.\n   if (!info->kern)\n      return 0;\n   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1\n      return 0;\n   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format\n      return 0;\n\n   return ttUSHORT(data+10);\n}\n\nSTBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningentry* table, int table_length)\n{\n   stbtt_uint8 *data = info->data + info->kern;\n   int k, length;\n\n   // we only look at the first table. it must be 'horizontal' and format 0.\n   if (!info->kern)\n      return 0;\n   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1\n      return 0;\n   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format\n      return 0;\n\n   length = ttUSHORT(data+10);\n   if (table_length < length)\n      length = table_length;\n\n   for (k = 0; k < length; k++)\n   {\n      table[k].glyph1 = ttUSHORT(data+18+(k*6));\n      table[k].glyph2 = ttUSHORT(data+20+(k*6));\n      table[k].advance = ttSHORT(data+22+(k*6));\n   }\n\n   return length;\n}\n\nstatic int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)\n{\n   stbtt_uint8 *data = info->data + info->kern;\n   stbtt_uint32 needle, straw;\n   int l, r, m;\n\n   // we only look at the first table. it must be 'horizontal' and format 0.\n   if (!info->kern)\n      return 0;\n   if (ttUSHORT(data+2) < 1) // number of tables, need at least 1\n      return 0;\n   if (ttUSHORT(data+8) != 1) // horizontal flag must be set in format\n      return 0;\n\n   l = 0;\n   r = ttUSHORT(data+10) - 1;\n   needle = glyph1 << 16 | glyph2;\n   while (l <= r) {\n      m = (l + r) >> 1;\n      straw = ttULONG(data+18+(m*6)); // note: unaligned read\n      if (needle < straw)\n         r = m - 1;\n      else if (needle > straw)\n         l = m + 1;\n      else\n         return ttSHORT(data+22+(m*6));\n   }\n   return 0;\n}\n\nstatic stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)\n{\n   stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);\n   switch (coverageFormat) {\n      case 1: {\n         stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);\n\n         // Binary search.\n         stbtt_int32 l=0, r=glyphCount-1, m;\n         int straw, needle=glyph;\n         while (l <= r) {\n            stbtt_uint8 *glyphArray = coverageTable + 4;\n            stbtt_uint16 glyphID;\n            m = (l + r) >> 1;\n            glyphID = ttUSHORT(glyphArray + 2 * m);\n            straw = glyphID;\n            if (needle < straw)\n               r = m - 1;\n            else if (needle > straw)\n               l = m + 1;\n            else {\n               return m;\n            }\n         }\n         break;\n      }\n\n      case 2: {\n         stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);\n         stbtt_uint8 *rangeArray = coverageTable + 4;\n\n         // Binary search.\n         stbtt_int32 l=0, r=rangeCount-1, m;\n         int strawStart, strawEnd, needle=glyph;\n         while (l <= r) {\n            stbtt_uint8 *rangeRecord;\n            m = (l + r) >> 1;\n            rangeRecord = rangeArray + 6 * m;\n            strawStart = ttUSHORT(rangeRecord);\n            strawEnd = ttUSHORT(rangeRecord + 2);\n            if (needle < strawStart)\n               r = m - 1;\n            else if (needle > strawEnd)\n               l = m + 1;\n            else {\n               stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);\n               return startCoverageIndex + glyph - strawStart;\n            }\n         }\n         break;\n      }\n\n      default: return -1; // unsupported\n   }\n\n   return -1;\n}\n\nstatic stbtt_int32  stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)\n{\n   stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);\n   switch (classDefFormat)\n   {\n      case 1: {\n         stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);\n         stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);\n         stbtt_uint8 *classDef1ValueArray = classDefTable + 6;\n\n         if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)\n            return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));\n         break;\n      }\n\n      case 2: {\n         stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);\n         stbtt_uint8 *classRangeRecords = classDefTable + 4;\n\n         // Binary search.\n         stbtt_int32 l=0, r=classRangeCount-1, m;\n         int strawStart, strawEnd, needle=glyph;\n         while (l <= r) {\n            stbtt_uint8 *classRangeRecord;\n            m = (l + r) >> 1;\n            classRangeRecord = classRangeRecords + 6 * m;\n            strawStart = ttUSHORT(classRangeRecord);\n            strawEnd = ttUSHORT(classRangeRecord + 2);\n            if (needle < strawStart)\n               r = m - 1;\n            else if (needle > strawEnd)\n               l = m + 1;\n            else\n               return (stbtt_int32)ttUSHORT(classRangeRecord + 4);\n         }\n         break;\n      }\n\n      default:\n         return -1; // Unsupported definition type, return an error.\n   }\n\n   // \"All glyphs not assigned to a class fall into class 0\". (OpenType spec)\n   return 0;\n}\n\n// Define to STBTT_assert(x) if you want to break on unimplemented formats.\n#define STBTT_GPOS_TODO_assert(x)\n\nstatic stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)\n{\n   stbtt_uint16 lookupListOffset;\n   stbtt_uint8 *lookupList;\n   stbtt_uint16 lookupCount;\n   stbtt_uint8 *data;\n   stbtt_int32 i, sti;\n\n   if (!info->gpos) return 0;\n\n   data = info->data + info->gpos;\n\n   if (ttUSHORT(data+0) != 1) return 0; // Major version 1\n   if (ttUSHORT(data+2) != 0) return 0; // Minor version 0\n\n   lookupListOffset = ttUSHORT(data+8);\n   lookupList = data + lookupListOffset;\n   lookupCount = ttUSHORT(lookupList);\n\n   for (i=0; i<lookupCount; ++i) {\n      stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);\n      stbtt_uint8 *lookupTable = lookupList + lookupOffset;\n\n      stbtt_uint16 lookupType = ttUSHORT(lookupTable);\n      stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);\n      stbtt_uint8 *subTableOffsets = lookupTable + 6;\n      if (lookupType != 2) // Pair Adjustment Positioning Subtable\n         continue;\n\n      for (sti=0; sti<subTableCount; sti++) {\n         stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);\n         stbtt_uint8 *table = lookupTable + subtableOffset;\n         stbtt_uint16 posFormat = ttUSHORT(table);\n         stbtt_uint16 coverageOffset = ttUSHORT(table + 2);\n         stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);\n         if (coverageIndex == -1) continue;\n\n         switch (posFormat) {\n            case 1: {\n               stbtt_int32 l, r, m;\n               int straw, needle;\n               stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);\n               stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);\n               if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?\n                  stbtt_int32 valueRecordPairSizeInBytes = 2;\n                  stbtt_uint16 pairSetCount = ttUSHORT(table + 8);\n                  stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);\n                  stbtt_uint8 *pairValueTable = table + pairPosOffset;\n                  stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);\n                  stbtt_uint8 *pairValueArray = pairValueTable + 2;\n\n                  if (coverageIndex >= pairSetCount) return 0;\n\n                  needle=glyph2;\n                  r=pairValueCount-1;\n                  l=0;\n\n                  // Binary search.\n                  while (l <= r) {\n                     stbtt_uint16 secondGlyph;\n                     stbtt_uint8 *pairValue;\n                     m = (l + r) >> 1;\n                     pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;\n                     secondGlyph = ttUSHORT(pairValue);\n                     straw = secondGlyph;\n                     if (needle < straw)\n                        r = m - 1;\n                     else if (needle > straw)\n                        l = m + 1;\n                     else {\n                        stbtt_int16 xAdvance = ttSHORT(pairValue + 2);\n                        return xAdvance;\n                     }\n                  }\n               } else\n                  return 0;\n               break;\n            }\n\n            case 2: {\n               stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);\n               stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);\n               if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?\n                  stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);\n                  stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);\n                  int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);\n                  int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);\n\n                  stbtt_uint16 class1Count = ttUSHORT(table + 12);\n                  stbtt_uint16 class2Count = ttUSHORT(table + 14);\n                  stbtt_uint8 *class1Records, *class2Records;\n                  stbtt_int16 xAdvance;\n\n                  if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed\n                  if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed\n\n                  class1Records = table + 16;\n                  class2Records = class1Records + 2 * (glyph1class * class2Count);\n                  xAdvance = ttSHORT(class2Records + 2 * glyph2class);\n                  return xAdvance;\n               } else\n                  return 0;\n               break;\n            }\n\n            default:\n               return 0; // Unsupported position format\n         }\n      }\n   }\n\n   return 0;\n}\n\nSTBTT_DEF int  stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)\n{\n   int xAdvance = 0;\n\n   if (info->gpos)\n      xAdvance += stbtt__GetGlyphGPOSInfoAdvance(info, g1, g2);\n   else if (info->kern)\n      xAdvance += stbtt__GetGlyphKernInfoAdvance(info, g1, g2);\n\n   return xAdvance;\n}\n\nSTBTT_DEF int  stbtt_GetCodepointKernAdvance(const stbtt_fontinfo *info, int ch1, int ch2)\n{\n   if (!info->kern && !info->gpos) // if no kerning table, don't waste time looking up both codepoint->glyphs\n      return 0;\n   return stbtt_GetGlyphKernAdvance(info, stbtt_FindGlyphIndex(info,ch1), stbtt_FindGlyphIndex(info,ch2));\n}\n\nSTBTT_DEF void stbtt_GetCodepointHMetrics(const stbtt_fontinfo *info, int codepoint, int *advanceWidth, int *leftSideBearing)\n{\n   stbtt_GetGlyphHMetrics(info, stbtt_FindGlyphIndex(info,codepoint), advanceWidth, leftSideBearing);\n}\n\nSTBTT_DEF void stbtt_GetFontVMetrics(const stbtt_fontinfo *info, int *ascent, int *descent, int *lineGap)\n{\n   if (ascent ) *ascent  = ttSHORT(info->data+info->hhea + 4);\n   if (descent) *descent = ttSHORT(info->data+info->hhea + 6);\n   if (lineGap) *lineGap = ttSHORT(info->data+info->hhea + 8);\n}\n\nSTBTT_DEF int  stbtt_GetFontVMetricsOS2(const stbtt_fontinfo *info, int *typoAscent, int *typoDescent, int *typoLineGap)\n{\n   int tab = stbtt__find_table(info->data, info->fontstart, \"OS/2\");\n   if (!tab)\n      return 0;\n   if (typoAscent ) *typoAscent  = ttSHORT(info->data+tab + 68);\n   if (typoDescent) *typoDescent = ttSHORT(info->data+tab + 70);\n   if (typoLineGap) *typoLineGap = ttSHORT(info->data+tab + 72);\n   return 1;\n}\n\nSTBTT_DEF void stbtt_GetFontBoundingBox(const stbtt_fontinfo *info, int *x0, int *y0, int *x1, int *y1)\n{\n   *x0 = ttSHORT(info->data + info->head + 36);\n   *y0 = ttSHORT(info->data + info->head + 38);\n   *x1 = ttSHORT(info->data + info->head + 40);\n   *y1 = ttSHORT(info->data + info->head + 42);\n}\n\nSTBTT_DEF float stbtt_ScaleForPixelHeight(const stbtt_fontinfo *info, float height)\n{\n   int fheight = ttSHORT(info->data + info->hhea + 4) - ttSHORT(info->data + info->hhea + 6);\n   return (float) height / fheight;\n}\n\nSTBTT_DEF float stbtt_ScaleForMappingEmToPixels(const stbtt_fontinfo *info, float pixels)\n{\n   int unitsPerEm = ttUSHORT(info->data + info->head + 18);\n   return pixels / unitsPerEm;\n}\n\nSTBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *v)\n{\n   STBTT_free(v, info->userdata);\n}\n\nSTBTT_DEF stbtt_uint8 *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl)\n{\n   int i;\n   stbtt_uint8 *data = info->data;\n   stbtt_uint8 *svg_doc_list = data + stbtt__get_svg((stbtt_fontinfo *) info);\n\n   int numEntries = ttUSHORT(svg_doc_list);\n   stbtt_uint8 *svg_docs = svg_doc_list + 2;\n\n   for(i=0; i<numEntries; i++) {\n      stbtt_uint8 *svg_doc = svg_docs + (12 * i);\n      if ((gl >= ttUSHORT(svg_doc)) && (gl <= ttUSHORT(svg_doc + 2)))\n         return svg_doc;\n   }\n   return 0;\n}\n\nSTBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg)\n{\n   stbtt_uint8 *data = info->data;\n   stbtt_uint8 *svg_doc;\n\n   if (info->svg == 0)\n      return 0;\n\n   svg_doc = stbtt_FindSVGDoc(info, gl);\n   if (svg_doc != NULL) {\n      *svg = (char *) data + info->svg + ttULONG(svg_doc + 4);\n      return ttULONG(svg_doc + 8);\n   } else {\n      return 0;\n   }\n}\n\nSTBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg)\n{\n   return stbtt_GetGlyphSVG(info, stbtt_FindGlyphIndex(info, unicode_codepoint), svg);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// antialiasing software rasterizer\n//\n\nSTBTT_DEF void stbtt_GetGlyphBitmapBoxSubpixel(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y,float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)\n{\n   int x0=0,y0=0,x1,y1; // =0 suppresses compiler warning\n   if (!stbtt_GetGlyphBox(font, glyph, &x0,&y0,&x1,&y1)) {\n      // e.g. space character\n      if (ix0) *ix0 = 0;\n      if (iy0) *iy0 = 0;\n      if (ix1) *ix1 = 0;\n      if (iy1) *iy1 = 0;\n   } else {\n      // move to integral bboxes (treating pixels as little squares, what pixels get touched)?\n      if (ix0) *ix0 = STBTT_ifloor( x0 * scale_x + shift_x);\n      if (iy0) *iy0 = STBTT_ifloor(-y1 * scale_y + shift_y);\n      if (ix1) *ix1 = STBTT_iceil ( x1 * scale_x + shift_x);\n      if (iy1) *iy1 = STBTT_iceil (-y0 * scale_y + shift_y);\n   }\n}\n\nSTBTT_DEF void stbtt_GetGlyphBitmapBox(const stbtt_fontinfo *font, int glyph, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)\n{\n   stbtt_GetGlyphBitmapBoxSubpixel(font, glyph, scale_x, scale_y,0.0f,0.0f, ix0, iy0, ix1, iy1);\n}\n\nSTBTT_DEF void stbtt_GetCodepointBitmapBoxSubpixel(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, float shift_x, float shift_y, int *ix0, int *iy0, int *ix1, int *iy1)\n{\n   stbtt_GetGlyphBitmapBoxSubpixel(font, stbtt_FindGlyphIndex(font,codepoint), scale_x, scale_y,shift_x,shift_y, ix0,iy0,ix1,iy1);\n}\n\nSTBTT_DEF void stbtt_GetCodepointBitmapBox(const stbtt_fontinfo *font, int codepoint, float scale_x, float scale_y, int *ix0, int *iy0, int *ix1, int *iy1)\n{\n   stbtt_GetCodepointBitmapBoxSubpixel(font, codepoint, scale_x, scale_y,0.0f,0.0f, ix0,iy0,ix1,iy1);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n//  Rasterizer\n\ntypedef struct stbtt__hheap_chunk\n{\n   struct stbtt__hheap_chunk *next;\n} stbtt__hheap_chunk;\n\ntypedef struct stbtt__hheap\n{\n   struct stbtt__hheap_chunk *head;\n   void   *first_free;\n   int    num_remaining_in_head_chunk;\n} stbtt__hheap;\n\nstatic void *stbtt__hheap_alloc(stbtt__hheap *hh, size_t size, void *userdata)\n{\n   if (hh->first_free) {\n      void *p = hh->first_free;\n      hh->first_free = * (void **) p;\n      return p;\n   } else {\n      if (hh->num_remaining_in_head_chunk == 0) {\n         int count = (size < 32 ? 2000 : size < 128 ? 800 : 100);\n         stbtt__hheap_chunk *c = (stbtt__hheap_chunk *) STBTT_malloc(sizeof(stbtt__hheap_chunk) + size * count, userdata);\n         if (c == NULL)\n            return NULL;\n         c->next = hh->head;\n         hh->head = c;\n         hh->num_remaining_in_head_chunk = count;\n      }\n      --hh->num_remaining_in_head_chunk;\n      return (char *) (hh->head) + sizeof(stbtt__hheap_chunk) + size * hh->num_remaining_in_head_chunk;\n   }\n}\n\nstatic void stbtt__hheap_free(stbtt__hheap *hh, void *p)\n{\n   *(void **) p = hh->first_free;\n   hh->first_free = p;\n}\n\nstatic void stbtt__hheap_cleanup(stbtt__hheap *hh, void *userdata)\n{\n   stbtt__hheap_chunk *c = hh->head;\n   while (c) {\n      stbtt__hheap_chunk *n = c->next;\n      STBTT_free(c, userdata);\n      c = n;\n   }\n}\n\ntypedef struct stbtt__edge {\n   float x0,y0, x1,y1;\n   int invert;\n} stbtt__edge;\n\n\ntypedef struct stbtt__active_edge\n{\n   struct stbtt__active_edge *next;\n   #if STBTT_RASTERIZER_VERSION==1\n   int x,dx;\n   float ey;\n   int direction;\n   #elif STBTT_RASTERIZER_VERSION==2\n   float fx,fdx,fdy;\n   float direction;\n   float sy;\n   float ey;\n   #else\n   #error \"Unrecognized value of STBTT_RASTERIZER_VERSION\"\n   #endif\n} stbtt__active_edge;\n\n#if STBTT_RASTERIZER_VERSION == 1\n#define STBTT_FIXSHIFT   10\n#define STBTT_FIX        (1 << STBTT_FIXSHIFT)\n#define STBTT_FIXMASK    (STBTT_FIX-1)\n\nstatic stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)\n{\n   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);\n   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);\n   STBTT_assert(z != NULL);\n   if (!z) return z;\n\n   // round dx down to avoid overshooting\n   if (dxdy < 0)\n      z->dx = -STBTT_ifloor(STBTT_FIX * -dxdy);\n   else\n      z->dx = STBTT_ifloor(STBTT_FIX * dxdy);\n\n   z->x = STBTT_ifloor(STBTT_FIX * e->x0 + z->dx * (start_point - e->y0)); // use z->dx so when we offset later it's by the same amount\n   z->x -= off_x * STBTT_FIX;\n\n   z->ey = e->y1;\n   z->next = 0;\n   z->direction = e->invert ? 1 : -1;\n   return z;\n}\n#elif STBTT_RASTERIZER_VERSION == 2\nstatic stbtt__active_edge *stbtt__new_active(stbtt__hheap *hh, stbtt__edge *e, int off_x, float start_point, void *userdata)\n{\n   stbtt__active_edge *z = (stbtt__active_edge *) stbtt__hheap_alloc(hh, sizeof(*z), userdata);\n   float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0);\n   STBTT_assert(z != NULL);\n   //STBTT_assert(e->y0 <= start_point);\n   if (!z) return z;\n   z->fdx = dxdy;\n   z->fdy = dxdy != 0.0f ? (1.0f/dxdy) : 0.0f;\n   z->fx = e->x0 + dxdy * (start_point - e->y0);\n   z->fx -= off_x;\n   z->direction = e->invert ? 1.0f : -1.0f;\n   z->sy = e->y0;\n   z->ey = e->y1;\n   z->next = 0;\n   return z;\n}\n#else\n#error \"Unrecognized value of STBTT_RASTERIZER_VERSION\"\n#endif\n\n#if STBTT_RASTERIZER_VERSION == 1\n// note: this routine clips fills that extend off the edges... ideally this\n// wouldn't happen, but it could happen if the truetype glyph bounding boxes\n// are wrong, or if the user supplies a too-small bitmap\nstatic void stbtt__fill_active_edges(unsigned char *scanline, int len, stbtt__active_edge *e, int max_weight)\n{\n   // non-zero winding fill\n   int x0=0, w=0;\n\n   while (e) {\n      if (w == 0) {\n         // if we're currently at zero, we need to record the edge start point\n         x0 = e->x; w += e->direction;\n      } else {\n         int x1 = e->x; w += e->direction;\n         // if we went to zero, we need to draw\n         if (w == 0) {\n            int i = x0 >> STBTT_FIXSHIFT;\n            int j = x1 >> STBTT_FIXSHIFT;\n\n            if (i < len && j >= 0) {\n               if (i == j) {\n                  // x0,x1 are the same pixel, so compute combined coverage\n                  scanline[i] = scanline[i] + (stbtt_uint8) ((x1 - x0) * max_weight >> STBTT_FIXSHIFT);\n               } else {\n                  if (i >= 0) // add antialiasing for x0\n                     scanline[i] = scanline[i] + (stbtt_uint8) (((STBTT_FIX - (x0 & STBTT_FIXMASK)) * max_weight) >> STBTT_FIXSHIFT);\n                  else\n                     i = -1; // clip\n\n                  if (j < len) // add antialiasing for x1\n                     scanline[j] = scanline[j] + (stbtt_uint8) (((x1 & STBTT_FIXMASK) * max_weight) >> STBTT_FIXSHIFT);\n                  else\n                     j = len; // clip\n\n                  for (++i; i < j; ++i) // fill pixels between x0 and x1\n                     scanline[i] = scanline[i] + (stbtt_uint8) max_weight;\n               }\n            }\n         }\n      }\n\n      e = e->next;\n   }\n}\n\nstatic void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)\n{\n   stbtt__hheap hh = { 0, 0, 0 };\n   stbtt__active_edge *active = NULL;\n   int y,j=0;\n   int max_weight = (255 / vsubsample);  // weight per vertical scanline\n   int s; // vertical subsample index\n   unsigned char scanline_data[512], *scanline;\n\n   if (result->w > 512)\n      scanline = (unsigned char *) STBTT_malloc(result->w, userdata);\n   else\n      scanline = scanline_data;\n\n   y = off_y * vsubsample;\n   e[n].y0 = (off_y + result->h) * (float) vsubsample + 1;\n\n   while (j < result->h) {\n      STBTT_memset(scanline, 0, result->w);\n      for (s=0; s < vsubsample; ++s) {\n         // find center of pixel for this scanline\n         float scan_y = y + 0.5f;\n         stbtt__active_edge **step = &active;\n\n         // update all active edges;\n         // remove all active edges that terminate before the center of this scanline\n         while (*step) {\n            stbtt__active_edge * z = *step;\n            if (z->ey <= scan_y) {\n               *step = z->next; // delete from list\n               STBTT_assert(z->direction);\n               z->direction = 0;\n               stbtt__hheap_free(&hh, z);\n            } else {\n               z->x += z->dx; // advance to position for current scanline\n               step = &((*step)->next); // advance through list\n            }\n         }\n\n         // resort the list if needed\n         for(;;) {\n            int changed=0;\n            step = &active;\n            while (*step && (*step)->next) {\n               if ((*step)->x > (*step)->next->x) {\n                  stbtt__active_edge *t = *step;\n                  stbtt__active_edge *q = t->next;\n\n                  t->next = q->next;\n                  q->next = t;\n                  *step = q;\n                  changed = 1;\n               }\n               step = &(*step)->next;\n            }\n            if (!changed) break;\n         }\n\n         // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline\n         while (e->y0 <= scan_y) {\n            if (e->y1 > scan_y) {\n               stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y, userdata);\n               if (z != NULL) {\n                  // find insertion point\n                  if (active == NULL)\n                     active = z;\n                  else if (z->x < active->x) {\n                     // insert at front\n                     z->next = active;\n                     active = z;\n                  } else {\n                     // find thing to insert AFTER\n                     stbtt__active_edge *p = active;\n                     while (p->next && p->next->x < z->x)\n                        p = p->next;\n                     // at this point, p->next->x is NOT < z->x\n                     z->next = p->next;\n                     p->next = z;\n                  }\n               }\n            }\n            ++e;\n         }\n\n         // now process all active edges in XOR fashion\n         if (active)\n            stbtt__fill_active_edges(scanline, result->w, active, max_weight);\n\n         ++y;\n      }\n      STBTT_memcpy(result->pixels + j * result->stride, scanline, result->w);\n      ++j;\n   }\n\n   stbtt__hheap_cleanup(&hh, userdata);\n\n   if (scanline != scanline_data)\n      STBTT_free(scanline, userdata);\n}\n\n#elif STBTT_RASTERIZER_VERSION == 2\n\n// the edge passed in here does not cross the vertical line at x or the vertical line at x+1\n// (i.e. it has already been clipped to those)\nstatic void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edge *e, float x0, float y0, float x1, float y1)\n{\n   if (y0 == y1) return;\n   STBTT_assert(y0 < y1);\n   STBTT_assert(e->sy <= e->ey);\n   if (y0 > e->ey) return;\n   if (y1 < e->sy) return;\n   if (y0 < e->sy) {\n      x0 += (x1-x0) * (e->sy - y0) / (y1-y0);\n      y0 = e->sy;\n   }\n   if (y1 > e->ey) {\n      x1 += (x1-x0) * (e->ey - y1) / (y1-y0);\n      y1 = e->ey;\n   }\n\n   if (x0 == x)\n      STBTT_assert(x1 <= x+1);\n   else if (x0 == x+1)\n      STBTT_assert(x1 >= x);\n   else if (x0 <= x)\n      STBTT_assert(x1 <= x);\n   else if (x0 >= x+1)\n      STBTT_assert(x1 >= x+1);\n   else\n      STBTT_assert(x1 >= x && x1 <= x+1);\n\n   if (x0 <= x && x1 <= x)\n      scanline[x] += e->direction * (y1-y0);\n   else if (x0 >= x+1 && x1 >= x+1)\n      ;\n   else {\n      STBTT_assert(x0 >= x && x0 <= x+1 && x1 >= x && x1 <= x+1);\n      scanline[x] += e->direction * (y1-y0) * (1-((x0-x)+(x1-x))/2); // coverage = 1 - average x position\n   }\n}\n\nstatic float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width)\n{\n   STBTT_assert(top_width >= 0);\n   STBTT_assert(bottom_width >= 0);\n   return (top_width + bottom_width) / 2.0f * height;\n}\n\nstatic float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1)\n{\n   return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);\n}\n\nstatic float stbtt__sized_triangle_area(float height, float width)\n{\n   return height * width / 2;\n}\n\nstatic void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)\n{\n   float y_bottom = y_top+1;\n\n   while (e) {\n      // brute force every pixel\n\n      // compute intersection points with top & bottom\n      STBTT_assert(e->ey >= y_top);\n\n      if (e->fdx == 0) {\n         float x0 = e->fx;\n         if (x0 < len) {\n            if (x0 >= 0) {\n               stbtt__handle_clipped_edge(scanline,(int) x0,e, x0,y_top, x0,y_bottom);\n               stbtt__handle_clipped_edge(scanline_fill-1,(int) x0+1,e, x0,y_top, x0,y_bottom);\n            } else {\n               stbtt__handle_clipped_edge(scanline_fill-1,0,e, x0,y_top, x0,y_bottom);\n            }\n         }\n      } else {\n         float x0 = e->fx;\n         float dx = e->fdx;\n         float xb = x0 + dx;\n         float x_top, x_bottom;\n         float sy0,sy1;\n         float dy = e->fdy;\n         STBTT_assert(e->sy <= y_bottom && e->ey >= y_top);\n\n         // compute endpoints of line segment clipped to this scanline (if the\n         // line segment starts on this scanline. x0 is the intersection of the\n         // line with y_top, but that may be off the line segment.\n         if (e->sy > y_top) {\n            x_top = x0 + dx * (e->sy - y_top);\n            sy0 = e->sy;\n         } else {\n            x_top = x0;\n            sy0 = y_top;\n         }\n         if (e->ey < y_bottom) {\n            x_bottom = x0 + dx * (e->ey - y_top);\n            sy1 = e->ey;\n         } else {\n            x_bottom = xb;\n            sy1 = y_bottom;\n         }\n\n         if (x_top >= 0 && x_bottom >= 0 && x_top < len && x_bottom < len) {\n            // from here on, we don't have to range check x values\n\n            if ((int) x_top == (int) x_bottom) {\n               float height;\n               // simple case, only spans one pixel\n               int x = (int) x_top;\n               height = (sy1 - sy0) * e->direction;\n               STBTT_assert(x >= 0 && x < len);\n               scanline[x]      += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);\n               scanline_fill[x] += height; // everything right of this pixel is filled\n            } else {\n               int x,x1,x2;\n               float y_crossing, y_final, step, sign, area;\n               // covers 2+ pixels\n               if (x_top > x_bottom) {\n                  // flip scanline vertically; signed area is the same\n                  float t;\n                  sy0 = y_bottom - (sy0 - y_top);\n                  sy1 = y_bottom - (sy1 - y_top);\n                  t = sy0, sy0 = sy1, sy1 = t;\n                  t = x_bottom, x_bottom = x_top, x_top = t;\n                  dx = -dx;\n                  dy = -dy;\n                  t = x0, x0 = xb, xb = t;\n               }\n               STBTT_assert(dy >= 0);\n               STBTT_assert(dx >= 0);\n\n               x1 = (int) x_top;\n               x2 = (int) x_bottom;\n               // compute intersection with y axis at x1+1\n               y_crossing = y_top + dy * (x1+1 - x0);\n\n               // compute intersection with y axis at x2\n               y_final = y_top + dy * (x2 - x0);\n\n               //           x1    x_top                            x2    x_bottom\n               //     y_top  +------|-----+------------+------------+--------|---+------------+\n               //            |            |            |            |            |            |\n               //            |            |            |            |            |            |\n               //       sy0  |      Txxxxx|............|............|............|............|\n               // y_crossing |            *xxxxx.......|............|............|............|\n               //            |            |     xxxxx..|............|............|............|\n               //            |            |     /-   xx*xxxx........|............|............|\n               //            |            | dy <       |    xxxxxx..|............|............|\n               //   y_final  |            |     \\-     |          xx*xxx.........|............|\n               //       sy1  |            |            |            |   xxxxxB...|............|\n               //            |            |            |            |            |            |\n               //            |            |            |            |            |            |\n               //  y_bottom  +------------+------------+------------+------------+------------+\n               //\n               // goal is to measure the area covered by '.' in each pixel\n\n               // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057\n               // @TODO: maybe test against sy1 rather than y_bottom?\n               if (y_crossing > y_bottom)\n                  y_crossing = y_bottom;\n\n               sign = e->direction;\n\n               // area of the rectangle covered from sy0..y_crossing\n               area = sign * (y_crossing-sy0);\n\n               // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing)\n               scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);\n\n               // check if final y_crossing is blown up; no test case for this\n               if (y_final > y_bottom) {\n                  y_final = y_bottom;\n                  dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom\n               }\n\n               // in second pixel, area covered by line segment found in first pixel\n               // is always a rectangle 1 wide * the height of that line segment; this\n               // is exactly what the variable 'area' stores. it also gets a contribution\n               // from the line segment within it. the THIRD pixel will get the first\n               // pixel's rectangle contribution, the second pixel's rectangle contribution,\n               // and its own contribution. the 'own contribution' is the same in every pixel except\n               // the leftmost and rightmost, a trapezoid that slides down in each pixel.\n               // the second pixel's contribution to the third pixel will be the\n               // rectangle 1 wide times the height change in the second pixel, which is dy.\n\n               step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x,\n               // which multiplied by 1-pixel-width is how much pixel area changes for each step in x\n               // so the area advances by 'step' every time\n\n               for (x = x1+1; x < x2; ++x) {\n                  scanline[x] += area + step/2; // area of trapezoid is 1*step/2\n                  area += step;\n               }\n               STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down\n               STBTT_assert(sy1 > y_final-0.01f);\n\n               // area covered in the last pixel is the rectangle from all the pixels to the left,\n               // plus the trapezoid filled by the line segment in this pixel all the way to the right edge\n               scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f);\n\n               // the rest of the line is filled based on the total height of the line segment in this pixel\n               scanline_fill[x2] += sign * (sy1-sy0);\n            }\n         } else {\n            // if edge goes outside of box we're drawing, we require\n            // clipping logic. since this does not match the intended use\n            // of this library, we use a different, very slow brute\n            // force implementation\n            // note though that this does happen some of the time because\n            // x_top and x_bottom can be extrapolated at the top & bottom of\n            // the shape and actually lie outside the bounding box\n            int x;\n            for (x=0; x < len; ++x) {\n               // cases:\n               //\n               // there can be up to two intersections with the pixel. any intersection\n               // with left or right edges can be handled by splitting into two (or three)\n               // regions. intersections with top & bottom do not necessitate case-wise logic.\n               //\n               // the old way of doing this found the intersections with the left & right edges,\n               // then used some simple logic to produce up to three segments in sorted order\n               // from top-to-bottom. however, this had a problem: if an x edge was epsilon\n               // across the x border, then the corresponding y position might not be distinct\n               // from the other y segment, and it might ignored as an empty segment. to avoid\n               // that, we need to explicitly produce segments based on x positions.\n\n               // rename variables to clearly-defined pairs\n               float y0 = y_top;\n               float x1 = (float) (x);\n               float x2 = (float) (x+1);\n               float x3 = xb;\n               float y3 = y_bottom;\n\n               // x = e->x + e->dx * (y-y_top)\n               // (y-y_top) = (x - e->x) / e->dx\n               // y = (x - e->x) / e->dx + y_top\n               float y1 = (x - x0) / dx + y_top;\n               float y2 = (x+1 - x0) / dx + y_top;\n\n               if (x0 < x1 && x3 > x2) {         // three segments descending down-right\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);\n                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x2,y2);\n                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);\n               } else if (x3 < x1 && x0 > x2) {  // three segments descending down-left\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);\n                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x1,y1);\n                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);\n               } else if (x0 < x1 && x3 > x1) {  // two segments across x, down-right\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);\n                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);\n               } else if (x3 < x1 && x0 > x1) {  // two segments across x, down-left\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x1,y1);\n                  stbtt__handle_clipped_edge(scanline,x,e, x1,y1, x3,y3);\n               } else if (x0 < x2 && x3 > x2) {  // two segments across x+1, down-right\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);\n                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);\n               } else if (x3 < x2 && x0 > x2) {  // two segments across x+1, down-left\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x2,y2);\n                  stbtt__handle_clipped_edge(scanline,x,e, x2,y2, x3,y3);\n               } else {  // one segment\n                  stbtt__handle_clipped_edge(scanline,x,e, x0,y0, x3,y3);\n               }\n            }\n         }\n      }\n      e = e->next;\n   }\n}\n\n// directly AA rasterize edges w/o supersampling\nstatic void stbtt__rasterize_sorted_edges(stbtt__bitmap *result, stbtt__edge *e, int n, int vsubsample, int off_x, int off_y, void *userdata)\n{\n   stbtt__hheap hh = { 0, 0, 0 };\n   stbtt__active_edge *active = NULL;\n   int y,j=0, i;\n   float scanline_data[129], *scanline, *scanline2;\n\n   STBTT__NOTUSED(vsubsample);\n\n   if (result->w > 64)\n      scanline = (float *) STBTT_malloc((result->w*2+1) * sizeof(float), userdata);\n   else\n      scanline = scanline_data;\n\n   scanline2 = scanline + result->w;\n\n   y = off_y;\n   e[n].y0 = (float) (off_y + result->h) + 1;\n\n   while (j < result->h) {\n      // find center of pixel for this scanline\n      float scan_y_top    = y + 0.0f;\n      float scan_y_bottom = y + 1.0f;\n      stbtt__active_edge **step = &active;\n\n      STBTT_memset(scanline , 0, result->w*sizeof(scanline[0]));\n      STBTT_memset(scanline2, 0, (result->w+1)*sizeof(scanline[0]));\n\n      // update all active edges;\n      // remove all active edges that terminate before the top of this scanline\n      while (*step) {\n         stbtt__active_edge * z = *step;\n         if (z->ey <= scan_y_top) {\n            *step = z->next; // delete from list\n            STBTT_assert(z->direction);\n            z->direction = 0;\n            stbtt__hheap_free(&hh, z);\n         } else {\n            step = &((*step)->next); // advance through list\n         }\n      }\n\n      // insert all edges that start before the bottom of this scanline\n      while (e->y0 <= scan_y_bottom) {\n         if (e->y0 != e->y1) {\n            stbtt__active_edge *z = stbtt__new_active(&hh, e, off_x, scan_y_top, userdata);\n            if (z != NULL) {\n               if (j == 0 && off_y != 0) {\n                  if (z->ey < scan_y_top) {\n                     // this can happen due to subpixel positioning and some kind of fp rounding error i think\n                     z->ey = scan_y_top;\n                  }\n               }\n               STBTT_assert(z->ey >= scan_y_top); // if we get really unlucky a tiny bit of an edge can be out of bounds\n               // insert at front\n               z->next = active;\n               active = z;\n            }\n         }\n         ++e;\n      }\n\n      // now process all active edges\n      if (active)\n         stbtt__fill_active_edges_new(scanline, scanline2+1, result->w, active, scan_y_top);\n\n      {\n         float sum = 0;\n         for (i=0; i < result->w; ++i) {\n            float k;\n            int m;\n            sum += scanline2[i];\n            k = scanline[i] + sum;\n            k = (float) STBTT_fabs(k)*255 + 0.5f;\n            m = (int) k;\n            if (m > 255) m = 255;\n            result->pixels[j*result->stride + i] = (unsigned char) m;\n         }\n      }\n      // advance all the edges\n      step = &active;\n      while (*step) {\n         stbtt__active_edge *z = *step;\n         z->fx += z->fdx; // advance to position for current scanline\n         step = &((*step)->next); // advance through list\n      }\n\n      ++y;\n      ++j;\n   }\n\n   stbtt__hheap_cleanup(&hh, userdata);\n\n   if (scanline != scanline_data)\n      STBTT_free(scanline, userdata);\n}\n#else\n#error \"Unrecognized value of STBTT_RASTERIZER_VERSION\"\n#endif\n\n#define STBTT__COMPARE(a,b)  ((a)->y0 < (b)->y0)\n\nstatic void stbtt__sort_edges_ins_sort(stbtt__edge *p, int n)\n{\n   int i,j;\n   for (i=1; i < n; ++i) {\n      stbtt__edge t = p[i], *a = &t;\n      j = i;\n      while (j > 0) {\n         stbtt__edge *b = &p[j-1];\n         int c = STBTT__COMPARE(a,b);\n         if (!c) break;\n         p[j] = p[j-1];\n         --j;\n      }\n      if (i != j)\n         p[j] = t;\n   }\n}\n\nstatic void stbtt__sort_edges_quicksort(stbtt__edge *p, int n)\n{\n   /* threshold for transitioning to insertion sort */\n   while (n > 12) {\n      stbtt__edge t;\n      int c01,c12,c,m,i,j;\n\n      /* compute median of three */\n      m = n >> 1;\n      c01 = STBTT__COMPARE(&p[0],&p[m]);\n      c12 = STBTT__COMPARE(&p[m],&p[n-1]);\n      /* if 0 >= mid >= end, or 0 < mid < end, then use mid */\n      if (c01 != c12) {\n         /* otherwise, we'll need to swap something else to middle */\n         int z;\n         c = STBTT__COMPARE(&p[0],&p[n-1]);\n         /* 0>mid && mid<n:  0>n => n; 0<n => 0 */\n         /* 0<mid && mid>n:  0>n => 0; 0<n => n */\n         z = (c == c12) ? 0 : n-1;\n         t = p[z];\n         p[z] = p[m];\n         p[m] = t;\n      }\n      /* now p[m] is the median-of-three */\n      /* swap it to the beginning so it won't move around */\n      t = p[0];\n      p[0] = p[m];\n      p[m] = t;\n\n      /* partition loop */\n      i=1;\n      j=n-1;\n      for(;;) {\n         /* handling of equality is crucial here */\n         /* for sentinels & efficiency with duplicates */\n         for (;;++i) {\n            if (!STBTT__COMPARE(&p[i], &p[0])) break;\n         }\n         for (;;--j) {\n            if (!STBTT__COMPARE(&p[0], &p[j])) break;\n         }\n         /* make sure we haven't crossed */\n         if (i >= j) break;\n         t = p[i];\n         p[i] = p[j];\n         p[j] = t;\n\n         ++i;\n         --j;\n      }\n      /* recurse on smaller side, iterate on larger */\n      if (j < (n-i)) {\n         stbtt__sort_edges_quicksort(p,j);\n         p = p+i;\n         n = n-i;\n      } else {\n         stbtt__sort_edges_quicksort(p+i, n-i);\n         n = j;\n      }\n   }\n}\n\nstatic void stbtt__sort_edges(stbtt__edge *p, int n)\n{\n   stbtt__sort_edges_quicksort(p, n);\n   stbtt__sort_edges_ins_sort(p, n);\n}\n\ntypedef struct\n{\n   float x,y;\n} stbtt__point;\n\nstatic void stbtt__rasterize(stbtt__bitmap *result, stbtt__point *pts, int *wcount, int windings, float scale_x, float scale_y, float shift_x, float shift_y, int off_x, int off_y, int invert, void *userdata)\n{\n   float y_scale_inv = invert ? -scale_y : scale_y;\n   stbtt__edge *e;\n   int n,i,j,k,m;\n#if STBTT_RASTERIZER_VERSION == 1\n   int vsubsample = result->h < 8 ? 15 : 5;\n#elif STBTT_RASTERIZER_VERSION == 2\n   int vsubsample = 1;\n#else\n   #error \"Unrecognized value of STBTT_RASTERIZER_VERSION\"\n#endif\n   // vsubsample should divide 255 evenly; otherwise we won't reach full opacity\n\n   // now we have to blow out the windings into explicit edge lists\n   n = 0;\n   for (i=0; i < windings; ++i)\n      n += wcount[i];\n\n   e = (stbtt__edge *) STBTT_malloc(sizeof(*e) * (n+1), userdata); // add an extra one as a sentinel\n   if (e == 0) return;\n   n = 0;\n\n   m=0;\n   for (i=0; i < windings; ++i) {\n      stbtt__point *p = pts + m;\n      m += wcount[i];\n      j = wcount[i]-1;\n      for (k=0; k < wcount[i]; j=k++) {\n         int a=k,b=j;\n         // skip the edge if horizontal\n         if (p[j].y == p[k].y)\n            continue;\n         // add edge from j to k to the list\n         e[n].invert = 0;\n         if (invert ? p[j].y > p[k].y : p[j].y < p[k].y) {\n            e[n].invert = 1;\n            a=j,b=k;\n         }\n         e[n].x0 = p[a].x * scale_x + shift_x;\n         e[n].y0 = (p[a].y * y_scale_inv + shift_y) * vsubsample;\n         e[n].x1 = p[b].x * scale_x + shift_x;\n         e[n].y1 = (p[b].y * y_scale_inv + shift_y) * vsubsample;\n         ++n;\n      }\n   }\n\n   // now sort the edges by their highest point (should snap to integer, and then by x)\n   //STBTT_sort(e, n, sizeof(e[0]), stbtt__edge_compare);\n   stbtt__sort_edges(e, n);\n\n   // now, traverse the scanlines and find the intersections on each scanline, use xor winding rule\n   stbtt__rasterize_sorted_edges(result, e, n, vsubsample, off_x, off_y, userdata);\n\n   STBTT_free(e, userdata);\n}\n\nstatic void stbtt__add_point(stbtt__point *points, int n, float x, float y)\n{\n   if (!points) return; // during first pass, it's unallocated\n   points[n].x = x;\n   points[n].y = y;\n}\n\n// tessellate until threshold p is happy... @TODO warped to compensate for non-linear stretching\nstatic int stbtt__tesselate_curve(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float objspace_flatness_squared, int n)\n{\n   // midpoint\n   float mx = (x0 + 2*x1 + x2)/4;\n   float my = (y0 + 2*y1 + y2)/4;\n   // versus directly drawn line\n   float dx = (x0+x2)/2 - mx;\n   float dy = (y0+y2)/2 - my;\n   if (n > 16) // 65536 segments on one curve better be enough!\n      return 1;\n   if (dx*dx+dy*dy > objspace_flatness_squared) { // half-pixel error allowed... need to be smaller if AA\n      stbtt__tesselate_curve(points, num_points, x0,y0, (x0+x1)/2.0f,(y0+y1)/2.0f, mx,my, objspace_flatness_squared,n+1);\n      stbtt__tesselate_curve(points, num_points, mx,my, (x1+x2)/2.0f,(y1+y2)/2.0f, x2,y2, objspace_flatness_squared,n+1);\n   } else {\n      stbtt__add_point(points, *num_points,x2,y2);\n      *num_points = *num_points+1;\n   }\n   return 1;\n}\n\nstatic void stbtt__tesselate_cubic(stbtt__point *points, int *num_points, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3, float objspace_flatness_squared, int n)\n{\n   // @TODO this \"flatness\" calculation is just made-up nonsense that seems to work well enough\n   float dx0 = x1-x0;\n   float dy0 = y1-y0;\n   float dx1 = x2-x1;\n   float dy1 = y2-y1;\n   float dx2 = x3-x2;\n   float dy2 = y3-y2;\n   float dx = x3-x0;\n   float dy = y3-y0;\n   float longlen = (float) (STBTT_sqrt(dx0*dx0+dy0*dy0)+STBTT_sqrt(dx1*dx1+dy1*dy1)+STBTT_sqrt(dx2*dx2+dy2*dy2));\n   float shortlen = (float) STBTT_sqrt(dx*dx+dy*dy);\n   float flatness_squared = longlen*longlen-shortlen*shortlen;\n\n   if (n > 16) // 65536 segments on one curve better be enough!\n      return;\n\n   if (flatness_squared > objspace_flatness_squared) {\n      float x01 = (x0+x1)/2;\n      float y01 = (y0+y1)/2;\n      float x12 = (x1+x2)/2;\n      float y12 = (y1+y2)/2;\n      float x23 = (x2+x3)/2;\n      float y23 = (y2+y3)/2;\n\n      float xa = (x01+x12)/2;\n      float ya = (y01+y12)/2;\n      float xb = (x12+x23)/2;\n      float yb = (y12+y23)/2;\n\n      float mx = (xa+xb)/2;\n      float my = (ya+yb)/2;\n\n      stbtt__tesselate_cubic(points, num_points, x0,y0, x01,y01, xa,ya, mx,my, objspace_flatness_squared,n+1);\n      stbtt__tesselate_cubic(points, num_points, mx,my, xb,yb, x23,y23, x3,y3, objspace_flatness_squared,n+1);\n   } else {\n      stbtt__add_point(points, *num_points,x3,y3);\n      *num_points = *num_points+1;\n   }\n}\n\n// returns number of contours\nstatic stbtt__point *stbtt_FlattenCurves(stbtt_vertex *vertices, int num_verts, float objspace_flatness, int **contour_lengths, int *num_contours, void *userdata)\n{\n   stbtt__point *points=0;\n   int num_points=0;\n\n   float objspace_flatness_squared = objspace_flatness * objspace_flatness;\n   int i,n=0,start=0, pass;\n\n   // count how many \"moves\" there are to get the contour count\n   for (i=0; i < num_verts; ++i)\n      if (vertices[i].type == STBTT_vmove)\n         ++n;\n\n   *num_contours = n;\n   if (n == 0) return 0;\n\n   *contour_lengths = (int *) STBTT_malloc(sizeof(**contour_lengths) * n, userdata);\n\n   if (*contour_lengths == 0) {\n      *num_contours = 0;\n      return 0;\n   }\n\n   // make two passes through the points so we don't need to realloc\n   for (pass=0; pass < 2; ++pass) {\n      float x=0,y=0;\n      if (pass == 1) {\n         points = (stbtt__point *) STBTT_malloc(num_points * sizeof(points[0]), userdata);\n         if (points == NULL) goto error;\n      }\n      num_points = 0;\n      n= -1;\n      for (i=0; i < num_verts; ++i) {\n         switch (vertices[i].type) {\n            case STBTT_vmove:\n               // start the next contour\n               if (n >= 0)\n                  (*contour_lengths)[n] = num_points - start;\n               ++n;\n               start = num_points;\n\n               x = vertices[i].x, y = vertices[i].y;\n               stbtt__add_point(points, num_points++, x,y);\n               break;\n            case STBTT_vline:\n               x = vertices[i].x, y = vertices[i].y;\n               stbtt__add_point(points, num_points++, x, y);\n               break;\n            case STBTT_vcurve:\n               stbtt__tesselate_curve(points, &num_points, x,y,\n                                        vertices[i].cx, vertices[i].cy,\n                                        vertices[i].x,  vertices[i].y,\n                                        objspace_flatness_squared, 0);\n               x = vertices[i].x, y = vertices[i].y;\n               break;\n            case STBTT_vcubic:\n               stbtt__tesselate_cubic(points, &num_points, x,y,\n                                        vertices[i].cx, vertices[i].cy,\n                                        vertices[i].cx1, vertices[i].cy1,\n                                        vertices[i].x,  vertices[i].y,\n                                        objspace_flatness_squared, 0);\n               x = vertices[i].x, y = vertices[i].y;\n               break;\n         }\n      }\n      (*contour_lengths)[n] = num_points - start;\n   }\n\n   return points;\nerror:\n   STBTT_free(points, userdata);\n   STBTT_free(*contour_lengths, userdata);\n   *contour_lengths = 0;\n   *num_contours = 0;\n   return NULL;\n}\n\nSTBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels, stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y, float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)\n{\n   float scale            = scale_x > scale_y ? scale_y : scale_x;\n   int winding_count      = 0;\n   int *winding_lengths   = NULL;\n   stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);\n   if (windings) {\n      stbtt__rasterize(result, windings, winding_lengths, winding_count, scale_x, scale_y, shift_x, shift_y, x_off, y_off, invert, userdata);\n      STBTT_free(winding_lengths, userdata);\n      STBTT_free(windings, userdata);\n   }\n}\n\nSTBTT_DEF void stbtt_FreeBitmap(unsigned char *bitmap, void *userdata)\n{\n   STBTT_free(bitmap, userdata);\n}\n\nSTBTT_DEF unsigned char *stbtt_GetGlyphBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int glyph, int *width, int *height, int *xoff, int *yoff)\n{\n   int ix0,iy0,ix1,iy1;\n   stbtt__bitmap gbm;\n   stbtt_vertex *vertices;\n   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);\n\n   if (scale_x == 0) scale_x = scale_y;\n   if (scale_y == 0) {\n      if (scale_x == 0) {\n         STBTT_free(vertices, info->userdata);\n         return NULL;\n      }\n      scale_y = scale_x;\n   }\n\n   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,&ix1,&iy1);\n\n   // now we get the size\n   gbm.w = (ix1 - ix0);\n   gbm.h = (iy1 - iy0);\n   gbm.pixels = NULL; // in case we error\n\n   if (width ) *width  = gbm.w;\n   if (height) *height = gbm.h;\n   if (xoff  ) *xoff   = ix0;\n   if (yoff  ) *yoff   = iy0;\n\n   if (gbm.w && gbm.h) {\n      gbm.pixels = (unsigned char *) STBTT_malloc(gbm.w * gbm.h, info->userdata);\n      if (gbm.pixels) {\n         gbm.stride = gbm.w;\n\n         stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0, iy0, 1, info->userdata);\n      }\n   }\n   STBTT_free(vertices, info->userdata);\n   return gbm.pixels;\n}\n\nSTBTT_DEF unsigned char *stbtt_GetGlyphBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int glyph, int *width, int *height, int *xoff, int *yoff)\n{\n   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y, 0.0f, 0.0f, glyph, width, height, xoff, yoff);\n}\n\nSTBTT_DEF void stbtt_MakeGlyphBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int glyph)\n{\n   int ix0,iy0;\n   stbtt_vertex *vertices;\n   int num_verts = stbtt_GetGlyphShape(info, glyph, &vertices);\n   stbtt__bitmap gbm;\n\n   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale_x, scale_y, shift_x, shift_y, &ix0,&iy0,0,0);\n   gbm.pixels = output;\n   gbm.w = out_w;\n   gbm.h = out_h;\n   gbm.stride = out_stride;\n\n   if (gbm.w && gbm.h)\n      stbtt_Rasterize(&gbm, 0.35f, vertices, num_verts, scale_x, scale_y, shift_x, shift_y, ix0,iy0, 1, info->userdata);\n\n   STBTT_free(vertices, info->userdata);\n}\n\nSTBTT_DEF void stbtt_MakeGlyphBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int glyph)\n{\n   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, glyph);\n}\n\nSTBTT_DEF unsigned char *stbtt_GetCodepointBitmapSubpixel(const stbtt_fontinfo *info, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint, int *width, int *height, int *xoff, int *yoff)\n{\n   return stbtt_GetGlyphBitmapSubpixel(info, scale_x, scale_y,shift_x,shift_y, stbtt_FindGlyphIndex(info,codepoint), width,height,xoff,yoff);\n}\n\nSTBTT_DEF void stbtt_MakeCodepointBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int oversample_x, int oversample_y, float *sub_x, float *sub_y, int codepoint)\n{\n   stbtt_MakeGlyphBitmapSubpixelPrefilter(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, oversample_x, oversample_y, sub_x, sub_y, stbtt_FindGlyphIndex(info,codepoint));\n}\n\nSTBTT_DEF void stbtt_MakeCodepointBitmapSubpixel(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int codepoint)\n{\n   stbtt_MakeGlyphBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, shift_x, shift_y, stbtt_FindGlyphIndex(info,codepoint));\n}\n\nSTBTT_DEF unsigned char *stbtt_GetCodepointBitmap(const stbtt_fontinfo *info, float scale_x, float scale_y, int codepoint, int *width, int *height, int *xoff, int *yoff)\n{\n   return stbtt_GetCodepointBitmapSubpixel(info, scale_x, scale_y, 0.0f,0.0f, codepoint, width,height,xoff,yoff);\n}\n\nSTBTT_DEF void stbtt_MakeCodepointBitmap(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, int codepoint)\n{\n   stbtt_MakeCodepointBitmapSubpixel(info, output, out_w, out_h, out_stride, scale_x, scale_y, 0.0f,0.0f, codepoint);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// bitmap baking\n//\n// This is SUPER-CRAPPY packing to keep source code small\n\nstatic int stbtt_BakeFontBitmap_internal(unsigned char *data, int offset,  // font location (use offset=0 for plain .ttf)\n                                float pixel_height,                     // height of font in pixels\n                                unsigned char *pixels, int pw, int ph,  // bitmap to be filled in\n                                int first_char, int num_chars,          // characters to bake\n                                stbtt_bakedchar *chardata)\n{\n   float scale;\n   int x,y,bottom_y, i;\n   stbtt_fontinfo f;\n   f.userdata = NULL;\n   if (!stbtt_InitFont(&f, data, offset))\n      return -1;\n   STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels\n   x=y=1;\n   bottom_y = 1;\n\n   scale = stbtt_ScaleForPixelHeight(&f, pixel_height);\n\n   for (i=0; i < num_chars; ++i) {\n      int advance, lsb, x0,y0,x1,y1,gw,gh;\n      int g = stbtt_FindGlyphIndex(&f, first_char + i);\n      stbtt_GetGlyphHMetrics(&f, g, &advance, &lsb);\n      stbtt_GetGlyphBitmapBox(&f, g, scale,scale, &x0,&y0,&x1,&y1);\n      gw = x1-x0;\n      gh = y1-y0;\n      if (x + gw + 1 >= pw)\n         y = bottom_y, x = 1; // advance to next row\n      if (y + gh + 1 >= ph) // check if it fits vertically AFTER potentially moving to next row\n         return -i;\n      STBTT_assert(x+gw < pw);\n      STBTT_assert(y+gh < ph);\n      stbtt_MakeGlyphBitmap(&f, pixels+x+y*pw, gw,gh,pw, scale,scale, g);\n      chardata[i].x0 = (stbtt_int16) x;\n      chardata[i].y0 = (stbtt_int16) y;\n      chardata[i].x1 = (stbtt_int16) (x + gw);\n      chardata[i].y1 = (stbtt_int16) (y + gh);\n      chardata[i].xadvance = scale * advance;\n      chardata[i].xoff     = (float) x0;\n      chardata[i].yoff     = (float) y0;\n      x = x + gw + 1;\n      if (y+gh+1 > bottom_y)\n         bottom_y = y+gh+1;\n   }\n   return bottom_y;\n}\n\nSTBTT_DEF void stbtt_GetBakedQuad(const stbtt_bakedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int opengl_fillrule)\n{\n   float d3d_bias = opengl_fillrule ? 0 : -0.5f;\n   float ipw = 1.0f / pw, iph = 1.0f / ph;\n   const stbtt_bakedchar *b = chardata + char_index;\n   int round_x = STBTT_ifloor((*xpos + b->xoff) + 0.5f);\n   int round_y = STBTT_ifloor((*ypos + b->yoff) + 0.5f);\n\n   q->x0 = round_x + d3d_bias;\n   q->y0 = round_y + d3d_bias;\n   q->x1 = round_x + b->x1 - b->x0 + d3d_bias;\n   q->y1 = round_y + b->y1 - b->y0 + d3d_bias;\n\n   q->s0 = b->x0 * ipw;\n   q->t0 = b->y0 * iph;\n   q->s1 = b->x1 * ipw;\n   q->t1 = b->y1 * iph;\n\n   *xpos += b->xadvance;\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// rectangle packing replacement routines if you don't have stb_rect_pack.h\n//\n\n#ifndef STB_RECT_PACK_VERSION\n\ntypedef int stbrp_coord;\n\n////////////////////////////////////////////////////////////////////////////////////\n//                                                                                //\n//                                                                                //\n// COMPILER WARNING ?!?!?                                                         //\n//                                                                                //\n//                                                                                //\n// if you get a compile warning due to these symbols being defined more than      //\n// once, move #include \"stb_rect_pack.h\" before #include \"stb_truetype.h\"         //\n//                                                                                //\n////////////////////////////////////////////////////////////////////////////////////\n\ntypedef struct\n{\n   int width,height;\n   int x,y,bottom_y;\n} stbrp_context;\n\ntypedef struct\n{\n   unsigned char x;\n} stbrp_node;\n\nstruct stbrp_rect\n{\n   stbrp_coord x,y;\n   int id,w,h,was_packed;\n};\n\nstatic void stbrp_init_target(stbrp_context *con, int pw, int ph, stbrp_node *nodes, int num_nodes)\n{\n   con->width  = pw;\n   con->height = ph;\n   con->x = 0;\n   con->y = 0;\n   con->bottom_y = 0;\n   STBTT__NOTUSED(nodes);\n   STBTT__NOTUSED(num_nodes);\n}\n\nstatic void stbrp_pack_rects(stbrp_context *con, stbrp_rect *rects, int num_rects)\n{\n   int i;\n   for (i=0; i < num_rects; ++i) {\n      if (con->x + rects[i].w > con->width) {\n         con->x = 0;\n         con->y = con->bottom_y;\n      }\n      if (con->y + rects[i].h > con->height)\n         break;\n      rects[i].x = con->x;\n      rects[i].y = con->y;\n      rects[i].was_packed = 1;\n      con->x += rects[i].w;\n      if (con->y + rects[i].h > con->bottom_y)\n         con->bottom_y = con->y + rects[i].h;\n   }\n   for (   ; i < num_rects; ++i)\n      rects[i].was_packed = 0;\n}\n#endif\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// bitmap baking\n//\n// This is SUPER-AWESOME (tm Ryan Gordon) packing using stb_rect_pack.h. If\n// stb_rect_pack.h isn't available, it uses the BakeFontBitmap strategy.\n\nSTBTT_DEF int stbtt_PackBegin(stbtt_pack_context *spc, unsigned char *pixels, int pw, int ph, int stride_in_bytes, int padding, void *alloc_context)\n{\n   stbrp_context *context = (stbrp_context *) STBTT_malloc(sizeof(*context)            ,alloc_context);\n   int            num_nodes = pw - padding;\n   stbrp_node    *nodes   = (stbrp_node    *) STBTT_malloc(sizeof(*nodes  ) * num_nodes,alloc_context);\n\n   if (context == NULL || nodes == NULL) {\n      if (context != NULL) STBTT_free(context, alloc_context);\n      if (nodes   != NULL) STBTT_free(nodes  , alloc_context);\n      return 0;\n   }\n\n   spc->user_allocator_context = alloc_context;\n   spc->width = pw;\n   spc->height = ph;\n   spc->pixels = pixels;\n   spc->pack_info = context;\n   spc->nodes = nodes;\n   spc->padding = padding;\n   spc->stride_in_bytes = stride_in_bytes != 0 ? stride_in_bytes : pw;\n   spc->h_oversample = 1;\n   spc->v_oversample = 1;\n   spc->skip_missing = 0;\n\n   stbrp_init_target(context, pw-padding, ph-padding, nodes, num_nodes);\n\n   if (pixels)\n      STBTT_memset(pixels, 0, pw*ph); // background of 0 around pixels\n\n   return 1;\n}\n\nSTBTT_DEF void stbtt_PackEnd  (stbtt_pack_context *spc)\n{\n   STBTT_free(spc->nodes    , spc->user_allocator_context);\n   STBTT_free(spc->pack_info, spc->user_allocator_context);\n}\n\nSTBTT_DEF void stbtt_PackSetOversampling(stbtt_pack_context *spc, unsigned int h_oversample, unsigned int v_oversample)\n{\n   STBTT_assert(h_oversample <= STBTT_MAX_OVERSAMPLE);\n   STBTT_assert(v_oversample <= STBTT_MAX_OVERSAMPLE);\n   if (h_oversample <= STBTT_MAX_OVERSAMPLE)\n      spc->h_oversample = h_oversample;\n   if (v_oversample <= STBTT_MAX_OVERSAMPLE)\n      spc->v_oversample = v_oversample;\n}\n\nSTBTT_DEF void stbtt_PackSetSkipMissingCodepoints(stbtt_pack_context *spc, int skip)\n{\n   spc->skip_missing = skip;\n}\n\n#define STBTT__OVER_MASK  (STBTT_MAX_OVERSAMPLE-1)\n\nstatic void stbtt__h_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)\n{\n   unsigned char buffer[STBTT_MAX_OVERSAMPLE];\n   int safe_w = w - kernel_width;\n   int j;\n   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze\n   for (j=0; j < h; ++j) {\n      int i;\n      unsigned int total;\n      STBTT_memset(buffer, 0, kernel_width);\n\n      total = 0;\n\n      // make kernel_width a constant in common cases so compiler can optimize out the divide\n      switch (kernel_width) {\n         case 2:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / 2);\n            }\n            break;\n         case 3:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / 3);\n            }\n            break;\n         case 4:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / 4);\n            }\n            break;\n         case 5:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / 5);\n            }\n            break;\n         default:\n            for (i=0; i <= safe_w; ++i) {\n               total += pixels[i] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i];\n               pixels[i] = (unsigned char) (total / kernel_width);\n            }\n            break;\n      }\n\n      for (; i < w; ++i) {\n         STBTT_assert(pixels[i] == 0);\n         total -= buffer[i & STBTT__OVER_MASK];\n         pixels[i] = (unsigned char) (total / kernel_width);\n      }\n\n      pixels += stride_in_bytes;\n   }\n}\n\nstatic void stbtt__v_prefilter(unsigned char *pixels, int w, int h, int stride_in_bytes, unsigned int kernel_width)\n{\n   unsigned char buffer[STBTT_MAX_OVERSAMPLE];\n   int safe_h = h - kernel_width;\n   int j;\n   STBTT_memset(buffer, 0, STBTT_MAX_OVERSAMPLE); // suppress bogus warning from VS2013 -analyze\n   for (j=0; j < w; ++j) {\n      int i;\n      unsigned int total;\n      STBTT_memset(buffer, 0, kernel_width);\n\n      total = 0;\n\n      // make kernel_width a constant in common cases so compiler can optimize out the divide\n      switch (kernel_width) {\n         case 2:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / 2);\n            }\n            break;\n         case 3:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / 3);\n            }\n            break;\n         case 4:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / 4);\n            }\n            break;\n         case 5:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / 5);\n            }\n            break;\n         default:\n            for (i=0; i <= safe_h; ++i) {\n               total += pixels[i*stride_in_bytes] - buffer[i & STBTT__OVER_MASK];\n               buffer[(i+kernel_width) & STBTT__OVER_MASK] = pixels[i*stride_in_bytes];\n               pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);\n            }\n            break;\n      }\n\n      for (; i < h; ++i) {\n         STBTT_assert(pixels[i*stride_in_bytes] == 0);\n         total -= buffer[i & STBTT__OVER_MASK];\n         pixels[i*stride_in_bytes] = (unsigned char) (total / kernel_width);\n      }\n\n      pixels += 1;\n   }\n}\n\nstatic float stbtt__oversample_shift(int oversample)\n{\n   if (!oversample)\n      return 0.0f;\n\n   // The prefilter is a box filter of width \"oversample\",\n   // which shifts phase by (oversample - 1)/2 pixels in\n   // oversampled space. We want to shift in the opposite\n   // direction to counter this.\n   return (float)-(oversample - 1) / (2.0f * (float)oversample);\n}\n\n// rects array must be big enough to accommodate all characters in the given ranges\nSTBTT_DEF int stbtt_PackFontRangesGatherRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)\n{\n   int i,j,k;\n   int missing_glyph_added = 0;\n\n   k=0;\n   for (i=0; i < num_ranges; ++i) {\n      float fh = ranges[i].font_size;\n      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);\n      ranges[i].h_oversample = (unsigned char) spc->h_oversample;\n      ranges[i].v_oversample = (unsigned char) spc->v_oversample;\n      for (j=0; j < ranges[i].num_chars; ++j) {\n         int x0,y0,x1,y1;\n         int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];\n         int glyph = stbtt_FindGlyphIndex(info, codepoint);\n         if (glyph == 0 && (spc->skip_missing || missing_glyph_added)) {\n            rects[k].w = rects[k].h = 0;\n         } else {\n            stbtt_GetGlyphBitmapBoxSubpixel(info,glyph,\n                                            scale * spc->h_oversample,\n                                            scale * spc->v_oversample,\n                                            0,0,\n                                            &x0,&y0,&x1,&y1);\n            rects[k].w = (stbrp_coord) (x1-x0 + spc->padding + spc->h_oversample-1);\n            rects[k].h = (stbrp_coord) (y1-y0 + spc->padding + spc->v_oversample-1);\n            if (glyph == 0)\n               missing_glyph_added = 1;\n         }\n         ++k;\n      }\n   }\n\n   return k;\n}\n\nSTBTT_DEF void stbtt_MakeGlyphBitmapSubpixelPrefilter(const stbtt_fontinfo *info, unsigned char *output, int out_w, int out_h, int out_stride, float scale_x, float scale_y, float shift_x, float shift_y, int prefilter_x, int prefilter_y, float *sub_x, float *sub_y, int glyph)\n{\n   stbtt_MakeGlyphBitmapSubpixel(info,\n                                 output,\n                                 out_w - (prefilter_x - 1),\n                                 out_h - (prefilter_y - 1),\n                                 out_stride,\n                                 scale_x,\n                                 scale_y,\n                                 shift_x,\n                                 shift_y,\n                                 glyph);\n\n   if (prefilter_x > 1)\n      stbtt__h_prefilter(output, out_w, out_h, out_stride, prefilter_x);\n\n   if (prefilter_y > 1)\n      stbtt__v_prefilter(output, out_w, out_h, out_stride, prefilter_y);\n\n   *sub_x = stbtt__oversample_shift(prefilter_x);\n   *sub_y = stbtt__oversample_shift(prefilter_y);\n}\n\n// rects array must be big enough to accommodate all characters in the given ranges\nSTBTT_DEF int stbtt_PackFontRangesRenderIntoRects(stbtt_pack_context *spc, const stbtt_fontinfo *info, stbtt_pack_range *ranges, int num_ranges, stbrp_rect *rects)\n{\n   int i,j,k, missing_glyph = -1, return_value = 1;\n\n   // save current values\n   int old_h_over = spc->h_oversample;\n   int old_v_over = spc->v_oversample;\n\n   k = 0;\n   for (i=0; i < num_ranges; ++i) {\n      float fh = ranges[i].font_size;\n      float scale = fh > 0 ? stbtt_ScaleForPixelHeight(info, fh) : stbtt_ScaleForMappingEmToPixels(info, -fh);\n      float recip_h,recip_v,sub_x,sub_y;\n      spc->h_oversample = ranges[i].h_oversample;\n      spc->v_oversample = ranges[i].v_oversample;\n      recip_h = 1.0f / spc->h_oversample;\n      recip_v = 1.0f / spc->v_oversample;\n      sub_x = stbtt__oversample_shift(spc->h_oversample);\n      sub_y = stbtt__oversample_shift(spc->v_oversample);\n      for (j=0; j < ranges[i].num_chars; ++j) {\n         stbrp_rect *r = &rects[k];\n         if (r->was_packed && r->w != 0 && r->h != 0) {\n            stbtt_packedchar *bc = &ranges[i].chardata_for_range[j];\n            int advance, lsb, x0,y0,x1,y1;\n            int codepoint = ranges[i].array_of_unicode_codepoints == NULL ? ranges[i].first_unicode_codepoint_in_range + j : ranges[i].array_of_unicode_codepoints[j];\n            int glyph = stbtt_FindGlyphIndex(info, codepoint);\n            stbrp_coord pad = (stbrp_coord) spc->padding;\n\n            // pad on left and top\n            r->x += pad;\n            r->y += pad;\n            r->w -= pad;\n            r->h -= pad;\n            stbtt_GetGlyphHMetrics(info, glyph, &advance, &lsb);\n            stbtt_GetGlyphBitmapBox(info, glyph,\n                                    scale * spc->h_oversample,\n                                    scale * spc->v_oversample,\n                                    &x0,&y0,&x1,&y1);\n            stbtt_MakeGlyphBitmapSubpixel(info,\n                                          spc->pixels + r->x + r->y*spc->stride_in_bytes,\n                                          r->w - spc->h_oversample+1,\n                                          r->h - spc->v_oversample+1,\n                                          spc->stride_in_bytes,\n                                          scale * spc->h_oversample,\n                                          scale * spc->v_oversample,\n                                          0,0,\n                                          glyph);\n\n            if (spc->h_oversample > 1)\n               stbtt__h_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,\n                                  r->w, r->h, spc->stride_in_bytes,\n                                  spc->h_oversample);\n\n            if (spc->v_oversample > 1)\n               stbtt__v_prefilter(spc->pixels + r->x + r->y*spc->stride_in_bytes,\n                                  r->w, r->h, spc->stride_in_bytes,\n                                  spc->v_oversample);\n\n            bc->x0       = (stbtt_int16)  r->x;\n            bc->y0       = (stbtt_int16)  r->y;\n            bc->x1       = (stbtt_int16) (r->x + r->w);\n            bc->y1       = (stbtt_int16) (r->y + r->h);\n            bc->xadvance =                scale * advance;\n            bc->xoff     =       (float)  x0 * recip_h + sub_x;\n            bc->yoff     =       (float)  y0 * recip_v + sub_y;\n            bc->xoff2    =                (x0 + r->w) * recip_h + sub_x;\n            bc->yoff2    =                (y0 + r->h) * recip_v + sub_y;\n\n            if (glyph == 0)\n               missing_glyph = j;\n         } else if (spc->skip_missing) {\n            return_value = 0;\n         } else if (r->was_packed && r->w == 0 && r->h == 0 && missing_glyph >= 0) {\n            ranges[i].chardata_for_range[j] = ranges[i].chardata_for_range[missing_glyph];\n         } else {\n            return_value = 0; // if any fail, report failure\n         }\n\n         ++k;\n      }\n   }\n\n   // restore original values\n   spc->h_oversample = old_h_over;\n   spc->v_oversample = old_v_over;\n\n   return return_value;\n}\n\nSTBTT_DEF void stbtt_PackFontRangesPackRects(stbtt_pack_context *spc, stbrp_rect *rects, int num_rects)\n{\n   stbrp_pack_rects((stbrp_context *) spc->pack_info, rects, num_rects);\n}\n\nSTBTT_DEF int stbtt_PackFontRanges(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, stbtt_pack_range *ranges, int num_ranges)\n{\n   stbtt_fontinfo info;\n   int i,j,n, return_value = 1;\n   //stbrp_context *context = (stbrp_context *) spc->pack_info;\n   stbrp_rect    *rects;\n\n   // flag all characters as NOT packed\n   for (i=0; i < num_ranges; ++i)\n      for (j=0; j < ranges[i].num_chars; ++j)\n         ranges[i].chardata_for_range[j].x0 =\n         ranges[i].chardata_for_range[j].y0 =\n         ranges[i].chardata_for_range[j].x1 =\n         ranges[i].chardata_for_range[j].y1 = 0;\n\n   n = 0;\n   for (i=0; i < num_ranges; ++i)\n      n += ranges[i].num_chars;\n\n   rects = (stbrp_rect *) STBTT_malloc(sizeof(*rects) * n, spc->user_allocator_context);\n   if (rects == NULL)\n      return 0;\n\n   info.userdata = spc->user_allocator_context;\n   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata,font_index));\n\n   n = stbtt_PackFontRangesGatherRects(spc, &info, ranges, num_ranges, rects);\n\n   stbtt_PackFontRangesPackRects(spc, rects, n);\n\n   return_value = stbtt_PackFontRangesRenderIntoRects(spc, &info, ranges, num_ranges, rects);\n\n   STBTT_free(rects, spc->user_allocator_context);\n   return return_value;\n}\n\nSTBTT_DEF int stbtt_PackFontRange(stbtt_pack_context *spc, const unsigned char *fontdata, int font_index, float font_size,\n            int first_unicode_codepoint_in_range, int num_chars_in_range, stbtt_packedchar *chardata_for_range)\n{\n   stbtt_pack_range range;\n   range.first_unicode_codepoint_in_range = first_unicode_codepoint_in_range;\n   range.array_of_unicode_codepoints = NULL;\n   range.num_chars                   = num_chars_in_range;\n   range.chardata_for_range          = chardata_for_range;\n   range.font_size                   = font_size;\n   return stbtt_PackFontRanges(spc, fontdata, font_index, &range, 1);\n}\n\nSTBTT_DEF void stbtt_GetScaledFontVMetrics(const unsigned char *fontdata, int index, float size, float *ascent, float *descent, float *lineGap)\n{\n   int i_ascent, i_descent, i_lineGap;\n   float scale;\n   stbtt_fontinfo info;\n   stbtt_InitFont(&info, fontdata, stbtt_GetFontOffsetForIndex(fontdata, index));\n   scale = size > 0 ? stbtt_ScaleForPixelHeight(&info, size) : stbtt_ScaleForMappingEmToPixels(&info, -size);\n   stbtt_GetFontVMetrics(&info, &i_ascent, &i_descent, &i_lineGap);\n   *ascent  = (float) i_ascent  * scale;\n   *descent = (float) i_descent * scale;\n   *lineGap = (float) i_lineGap * scale;\n}\n\nSTBTT_DEF void stbtt_GetPackedQuad(const stbtt_packedchar *chardata, int pw, int ph, int char_index, float *xpos, float *ypos, stbtt_aligned_quad *q, int align_to_integer)\n{\n   float ipw = 1.0f / pw, iph = 1.0f / ph;\n   const stbtt_packedchar *b = chardata + char_index;\n\n   if (align_to_integer) {\n      float x = (float) STBTT_ifloor((*xpos + b->xoff) + 0.5f);\n      float y = (float) STBTT_ifloor((*ypos + b->yoff) + 0.5f);\n      q->x0 = x;\n      q->y0 = y;\n      q->x1 = x + b->xoff2 - b->xoff;\n      q->y1 = y + b->yoff2 - b->yoff;\n   } else {\n      q->x0 = *xpos + b->xoff;\n      q->y0 = *ypos + b->yoff;\n      q->x1 = *xpos + b->xoff2;\n      q->y1 = *ypos + b->yoff2;\n   }\n\n   q->s0 = b->x0 * ipw;\n   q->t0 = b->y0 * iph;\n   q->s1 = b->x1 * ipw;\n   q->t1 = b->y1 * iph;\n\n   *xpos += b->xadvance;\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// sdf computation\n//\n\n#define STBTT_min(a,b)  ((a) < (b) ? (a) : (b))\n#define STBTT_max(a,b)  ((a) < (b) ? (b) : (a))\n\nstatic int stbtt__ray_intersect_bezier(float orig[2], float ray[2], float q0[2], float q1[2], float q2[2], float hits[2][2])\n{\n   float q0perp = q0[1]*ray[0] - q0[0]*ray[1];\n   float q1perp = q1[1]*ray[0] - q1[0]*ray[1];\n   float q2perp = q2[1]*ray[0] - q2[0]*ray[1];\n   float roperp = orig[1]*ray[0] - orig[0]*ray[1];\n\n   float a = q0perp - 2*q1perp + q2perp;\n   float b = q1perp - q0perp;\n   float c = q0perp - roperp;\n\n   float s0 = 0., s1 = 0.;\n   int num_s = 0;\n\n   if (a != 0.0) {\n      float discr = b*b - a*c;\n      if (discr > 0.0) {\n         float rcpna = -1 / a;\n         float d = (float) STBTT_sqrt(discr);\n         s0 = (b+d) * rcpna;\n         s1 = (b-d) * rcpna;\n         if (s0 >= 0.0 && s0 <= 1.0)\n            num_s = 1;\n         if (d > 0.0 && s1 >= 0.0 && s1 <= 1.0) {\n            if (num_s == 0) s0 = s1;\n            ++num_s;\n         }\n      }\n   } else {\n      // 2*b*s + c = 0\n      // s = -c / (2*b)\n      s0 = c / (-2 * b);\n      if (s0 >= 0.0 && s0 <= 1.0)\n         num_s = 1;\n   }\n\n   if (num_s == 0)\n      return 0;\n   else {\n      float rcp_len2 = 1 / (ray[0]*ray[0] + ray[1]*ray[1]);\n      float rayn_x = ray[0] * rcp_len2, rayn_y = ray[1] * rcp_len2;\n\n      float q0d =   q0[0]*rayn_x +   q0[1]*rayn_y;\n      float q1d =   q1[0]*rayn_x +   q1[1]*rayn_y;\n      float q2d =   q2[0]*rayn_x +   q2[1]*rayn_y;\n      float rod = orig[0]*rayn_x + orig[1]*rayn_y;\n\n      float q10d = q1d - q0d;\n      float q20d = q2d - q0d;\n      float q0rd = q0d - rod;\n\n      hits[0][0] = q0rd + s0*(2.0f - 2.0f*s0)*q10d + s0*s0*q20d;\n      hits[0][1] = a*s0+b;\n\n      if (num_s > 1) {\n         hits[1][0] = q0rd + s1*(2.0f - 2.0f*s1)*q10d + s1*s1*q20d;\n         hits[1][1] = a*s1+b;\n         return 2;\n      } else {\n         return 1;\n      }\n   }\n}\n\nstatic int stbtt__equal(float *a, float *b)\n{\n   return (a[0] == b[0] && a[1] == b[1]);\n}\n\nstatic int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex *verts)\n{\n   int i;\n   float orig[2], ray[2] = { 1, 0 };\n   float y_frac;\n   int winding = 0;\n\n   // make sure y never passes through a vertex of the shape\n   y_frac = (float) STBTT_fmod(y, 1.0f);\n   if (y_frac < 0.01f)\n      y += 0.01f;\n   else if (y_frac > 0.99f)\n      y -= 0.01f;\n\n   orig[0] = x;\n   orig[1] = y;\n\n   // test a ray from (-infinity,y) to (x,y)\n   for (i=0; i < nverts; ++i) {\n      if (verts[i].type == STBTT_vline) {\n         int x0 = (int) verts[i-1].x, y0 = (int) verts[i-1].y;\n         int x1 = (int) verts[i  ].x, y1 = (int) verts[i  ].y;\n         if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {\n            float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;\n            if (x_inter < x)\n               winding += (y0 < y1) ? 1 : -1;\n         }\n      }\n      if (verts[i].type == STBTT_vcurve) {\n         int x0 = (int) verts[i-1].x , y0 = (int) verts[i-1].y ;\n         int x1 = (int) verts[i  ].cx, y1 = (int) verts[i  ].cy;\n         int x2 = (int) verts[i  ].x , y2 = (int) verts[i  ].y ;\n         int ax = STBTT_min(x0,STBTT_min(x1,x2)), ay = STBTT_min(y0,STBTT_min(y1,y2));\n         int by = STBTT_max(y0,STBTT_max(y1,y2));\n         if (y > ay && y < by && x > ax) {\n            float q0[2],q1[2],q2[2];\n            float hits[2][2];\n            q0[0] = (float)x0;\n            q0[1] = (float)y0;\n            q1[0] = (float)x1;\n            q1[1] = (float)y1;\n            q2[0] = (float)x2;\n            q2[1] = (float)y2;\n            if (stbtt__equal(q0,q1) || stbtt__equal(q1,q2)) {\n               x0 = (int)verts[i-1].x;\n               y0 = (int)verts[i-1].y;\n               x1 = (int)verts[i  ].x;\n               y1 = (int)verts[i  ].y;\n               if (y > STBTT_min(y0,y1) && y < STBTT_max(y0,y1) && x > STBTT_min(x0,x1)) {\n                  float x_inter = (y - y0) / (y1 - y0) * (x1-x0) + x0;\n                  if (x_inter < x)\n                     winding += (y0 < y1) ? 1 : -1;\n               }\n            } else {\n               int num_hits = stbtt__ray_intersect_bezier(orig, ray, q0, q1, q2, hits);\n               if (num_hits >= 1)\n                  if (hits[0][0] < 0)\n                     winding += (hits[0][1] < 0 ? -1 : 1);\n               if (num_hits >= 2)\n                  if (hits[1][0] < 0)\n                     winding += (hits[1][1] < 0 ? -1 : 1);\n            }\n         }\n      }\n   }\n   return winding;\n}\n\nstatic float stbtt__cuberoot( float x )\n{\n   if (x<0)\n      return -(float) STBTT_pow(-x,1.0f/3.0f);\n   else\n      return  (float) STBTT_pow( x,1.0f/3.0f);\n}\n\n// x^3 + a*x^2 + b*x + c = 0\nstatic int stbtt__solve_cubic(float a, float b, float c, float* r)\n{\n   float s = -a / 3;\n   float p = b - a*a / 3;\n   float q = a * (2*a*a - 9*b) / 27 + c;\n   float p3 = p*p*p;\n   float d = q*q + 4*p3 / 27;\n   if (d >= 0) {\n      float z = (float) STBTT_sqrt(d);\n      float u = (-q + z) / 2;\n      float v = (-q - z) / 2;\n      u = stbtt__cuberoot(u);\n      v = stbtt__cuberoot(v);\n      r[0] = s + u + v;\n      return 1;\n   } else {\n      float u = (float) STBTT_sqrt(-p/3);\n      float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative\n      float m = (float) STBTT_cos(v);\n      float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;\n      r[0] = s + u * 2 * m;\n      r[1] = s - u * (m + n);\n      r[2] = s - u * (m - n);\n\n      //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f);  // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?\n      //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);\n      //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);\n      return 3;\n   }\n}\n\nSTBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float scale, int glyph, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)\n{\n   float scale_x = scale, scale_y = scale;\n   int ix0,iy0,ix1,iy1;\n   int w,h;\n   unsigned char *data;\n\n   if (scale == 0) return NULL;\n\n   stbtt_GetGlyphBitmapBoxSubpixel(info, glyph, scale, scale, 0.0f,0.0f, &ix0,&iy0,&ix1,&iy1);\n\n   // if empty, return NULL\n   if (ix0 == ix1 || iy0 == iy1)\n      return NULL;\n\n   ix0 -= padding;\n   iy0 -= padding;\n   ix1 += padding;\n   iy1 += padding;\n\n   w = (ix1 - ix0);\n   h = (iy1 - iy0);\n\n   if (width ) *width  = w;\n   if (height) *height = h;\n   if (xoff  ) *xoff   = ix0;\n   if (yoff  ) *yoff   = iy0;\n\n   // invert for y-downwards bitmaps\n   scale_y = -scale_y;\n\n   {\n      int x,y,i,j;\n      float *precompute;\n      stbtt_vertex *verts;\n      int num_verts = stbtt_GetGlyphShape(info, glyph, &verts);\n      data = (unsigned char *) STBTT_malloc(w * h, info->userdata);\n      precompute = (float *) STBTT_malloc(num_verts * sizeof(float), info->userdata);\n\n      for (i=0,j=num_verts-1; i < num_verts; j=i++) {\n         if (verts[i].type == STBTT_vline) {\n            float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;\n            float x1 = verts[j].x*scale_x, y1 = verts[j].y*scale_y;\n            float dist = (float) STBTT_sqrt((x1-x0)*(x1-x0) + (y1-y0)*(y1-y0));\n            precompute[i] = (dist == 0) ? 0.0f : 1.0f / dist;\n         } else if (verts[i].type == STBTT_vcurve) {\n            float x2 = verts[j].x *scale_x, y2 = verts[j].y *scale_y;\n            float x1 = verts[i].cx*scale_x, y1 = verts[i].cy*scale_y;\n            float x0 = verts[i].x *scale_x, y0 = verts[i].y *scale_y;\n            float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;\n            float len2 = bx*bx + by*by;\n            if (len2 != 0.0f)\n               precompute[i] = 1.0f / (bx*bx + by*by);\n            else\n               precompute[i] = 0.0f;\n         } else\n            precompute[i] = 0.0f;\n      }\n\n      for (y=iy0; y < iy1; ++y) {\n         for (x=ix0; x < ix1; ++x) {\n            float val;\n            float min_dist = 999999.0f;\n            float sx = (float) x + 0.5f;\n            float sy = (float) y + 0.5f;\n            float x_gspace = (sx / scale_x);\n            float y_gspace = (sy / scale_y);\n\n            int winding = stbtt__compute_crossings_x(x_gspace, y_gspace, num_verts, verts); // @OPTIMIZE: this could just be a rasterization, but needs to be line vs. non-tesselated curves so a new path\n\n            for (i=0; i < num_verts; ++i) {\n               float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;\n\n               if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {\n                  float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;\n\n                  float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);\n                  if (dist2 < min_dist*min_dist)\n                     min_dist = (float) STBTT_sqrt(dist2);\n\n                  // coarse culling against bbox\n                  //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&\n                  //    sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)\n                  dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];\n                  STBTT_assert(i != 0);\n                  if (dist < min_dist) {\n                     // check position along line\n                     // x' = x0 + t*(x1-x0), y' = y0 + t*(y1-y0)\n                     // minimize (x'-sx)*(x'-sx)+(y'-sy)*(y'-sy)\n                     float dx = x1-x0, dy = y1-y0;\n                     float px = x0-sx, py = y0-sy;\n                     // minimize (px+t*dx)^2 + (py+t*dy)^2 = px*px + 2*px*dx*t + t^2*dx*dx + py*py + 2*py*dy*t + t^2*dy*dy\n                     // derivative: 2*px*dx + 2*py*dy + (2*dx*dx+2*dy*dy)*t, set to 0 and solve\n                     float t = -(px*dx + py*dy) / (dx*dx + dy*dy);\n                     if (t >= 0.0f && t <= 1.0f)\n                        min_dist = dist;\n                  }\n               } else if (verts[i].type == STBTT_vcurve) {\n                  float x2 = verts[i-1].x *scale_x, y2 = verts[i-1].y *scale_y;\n                  float x1 = verts[i  ].cx*scale_x, y1 = verts[i  ].cy*scale_y;\n                  float box_x0 = STBTT_min(STBTT_min(x0,x1),x2);\n                  float box_y0 = STBTT_min(STBTT_min(y0,y1),y2);\n                  float box_x1 = STBTT_max(STBTT_max(x0,x1),x2);\n                  float box_y1 = STBTT_max(STBTT_max(y0,y1),y2);\n                  // coarse culling against bbox to avoid computing cubic unnecessarily\n                  if (sx > box_x0-min_dist && sx < box_x1+min_dist && sy > box_y0-min_dist && sy < box_y1+min_dist) {\n                     int num=0;\n                     float ax = x1-x0, ay = y1-y0;\n                     float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;\n                     float mx = x0 - sx, my = y0 - sy;\n                     float res[3] = {0.f,0.f,0.f};\n                     float px,py,t,it,dist2;\n                     float a_inv = precompute[i];\n                     if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula\n                        float a = 3*(ax*bx + ay*by);\n                        float b = 2*(ax*ax + ay*ay) + (mx*bx+my*by);\n                        float c = mx*ax+my*ay;\n                        if (a == 0.0) { // if a is 0, it's linear\n                           if (b != 0.0) {\n                              res[num++] = -c/b;\n                           }\n                        } else {\n                           float discriminant = b*b - 4*a*c;\n                           if (discriminant < 0)\n                              num = 0;\n                           else {\n                              float root = (float) STBTT_sqrt(discriminant);\n                              res[0] = (-b - root)/(2*a);\n                              res[1] = (-b + root)/(2*a);\n                              num = 2; // don't bother distinguishing 1-solution case, as code below will still work\n                           }\n                        }\n                     } else {\n                        float b = 3*(ax*bx + ay*by) * a_inv; // could precompute this as it doesn't depend on sample point\n                        float c = (2*(ax*ax + ay*ay) + (mx*bx+my*by)) * a_inv;\n                        float d = (mx*ax+my*ay) * a_inv;\n                        num = stbtt__solve_cubic(b, c, d, res);\n                     }\n                     dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);\n                     if (dist2 < min_dist*min_dist)\n                        min_dist = (float) STBTT_sqrt(dist2);\n\n                     if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {\n                        t = res[0], it = 1.0f - t;\n                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;\n                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;\n                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);\n                        if (dist2 < min_dist * min_dist)\n                           min_dist = (float) STBTT_sqrt(dist2);\n                     }\n                     if (num >= 2 && res[1] >= 0.0f && res[1] <= 1.0f) {\n                        t = res[1], it = 1.0f - t;\n                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;\n                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;\n                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);\n                        if (dist2 < min_dist * min_dist)\n                           min_dist = (float) STBTT_sqrt(dist2);\n                     }\n                     if (num >= 3 && res[2] >= 0.0f && res[2] <= 1.0f) {\n                        t = res[2], it = 1.0f - t;\n                        px = it*it*x0 + 2*t*it*x1 + t*t*x2;\n                        py = it*it*y0 + 2*t*it*y1 + t*t*y2;\n                        dist2 = (px-sx)*(px-sx) + (py-sy)*(py-sy);\n                        if (dist2 < min_dist * min_dist)\n                           min_dist = (float) STBTT_sqrt(dist2);\n                     }\n                  }\n               }\n            }\n            if (winding == 0)\n               min_dist = -min_dist;  // if outside the shape, value is negative\n            val = onedge_value + pixel_dist_scale * min_dist;\n            if (val < 0)\n               val = 0;\n            else if (val > 255)\n               val = 255;\n            data[(y-iy0)*w+(x-ix0)] = (unsigned char) val;\n         }\n      }\n      STBTT_free(precompute, info->userdata);\n      STBTT_free(verts, info->userdata);\n   }\n   return data;\n}\n\nSTBTT_DEF unsigned char * stbtt_GetCodepointSDF(const stbtt_fontinfo *info, float scale, int codepoint, int padding, unsigned char onedge_value, float pixel_dist_scale, int *width, int *height, int *xoff, int *yoff)\n{\n   return stbtt_GetGlyphSDF(info, scale, stbtt_FindGlyphIndex(info, codepoint), padding, onedge_value, pixel_dist_scale, width, height, xoff, yoff);\n}\n\nSTBTT_DEF void stbtt_FreeSDF(unsigned char *bitmap, void *userdata)\n{\n   STBTT_free(bitmap, userdata);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n//\n// font name matching -- recommended not to use this\n//\n\n// check if a utf8 string contains a prefix which is the utf16 string; if so return length of matching utf8 string\nstatic stbtt_int32 stbtt__CompareUTF8toUTF16_bigendian_prefix(stbtt_uint8 *s1, stbtt_int32 len1, stbtt_uint8 *s2, stbtt_int32 len2)\n{\n   stbtt_int32 i=0;\n\n   // convert utf16 to utf8 and compare the results while converting\n   while (len2) {\n      stbtt_uint16 ch = s2[0]*256 + s2[1];\n      if (ch < 0x80) {\n         if (i >= len1) return -1;\n         if (s1[i++] != ch) return -1;\n      } else if (ch < 0x800) {\n         if (i+1 >= len1) return -1;\n         if (s1[i++] != 0xc0 + (ch >> 6)) return -1;\n         if (s1[i++] != 0x80 + (ch & 0x3f)) return -1;\n      } else if (ch >= 0xd800 && ch < 0xdc00) {\n         stbtt_uint32 c;\n         stbtt_uint16 ch2 = s2[2]*256 + s2[3];\n         if (i+3 >= len1) return -1;\n         c = ((ch - 0xd800) << 10) + (ch2 - 0xdc00) + 0x10000;\n         if (s1[i++] != 0xf0 + (c >> 18)) return -1;\n         if (s1[i++] != 0x80 + ((c >> 12) & 0x3f)) return -1;\n         if (s1[i++] != 0x80 + ((c >>  6) & 0x3f)) return -1;\n         if (s1[i++] != 0x80 + ((c      ) & 0x3f)) return -1;\n         s2 += 2; // plus another 2 below\n         len2 -= 2;\n      } else if (ch >= 0xdc00 && ch < 0xe000) {\n         return -1;\n      } else {\n         if (i+2 >= len1) return -1;\n         if (s1[i++] != 0xe0 + (ch >> 12)) return -1;\n         if (s1[i++] != 0x80 + ((ch >> 6) & 0x3f)) return -1;\n         if (s1[i++] != 0x80 + ((ch     ) & 0x3f)) return -1;\n      }\n      s2 += 2;\n      len2 -= 2;\n   }\n   return i;\n}\n\nstatic int stbtt_CompareUTF8toUTF16_bigendian_internal(char *s1, int len1, char *s2, int len2)\n{\n   return len1 == stbtt__CompareUTF8toUTF16_bigendian_prefix((stbtt_uint8*) s1, len1, (stbtt_uint8*) s2, len2);\n}\n\n// returns results in whatever encoding you request... but note that 2-byte encodings\n// will be BIG-ENDIAN... use stbtt_CompareUTF8toUTF16_bigendian() to compare\nSTBTT_DEF const char *stbtt_GetFontNameString(const stbtt_fontinfo *font, int *length, int platformID, int encodingID, int languageID, int nameID)\n{\n   stbtt_int32 i,count,stringOffset;\n   stbtt_uint8 *fc = font->data;\n   stbtt_uint32 offset = font->fontstart;\n   stbtt_uint32 nm = stbtt__find_table(fc, offset, \"name\");\n   if (!nm) return NULL;\n\n   count = ttUSHORT(fc+nm+2);\n   stringOffset = nm + ttUSHORT(fc+nm+4);\n   for (i=0; i < count; ++i) {\n      stbtt_uint32 loc = nm + 6 + 12 * i;\n      if (platformID == ttUSHORT(fc+loc+0) && encodingID == ttUSHORT(fc+loc+2)\n          && languageID == ttUSHORT(fc+loc+4) && nameID == ttUSHORT(fc+loc+6)) {\n         *length = ttUSHORT(fc+loc+8);\n         return (const char *) (fc+stringOffset+ttUSHORT(fc+loc+10));\n      }\n   }\n   return NULL;\n}\n\nstatic int stbtt__matchpair(stbtt_uint8 *fc, stbtt_uint32 nm, stbtt_uint8 *name, stbtt_int32 nlen, stbtt_int32 target_id, stbtt_int32 next_id)\n{\n   stbtt_int32 i;\n   stbtt_int32 count = ttUSHORT(fc+nm+2);\n   stbtt_int32 stringOffset = nm + ttUSHORT(fc+nm+4);\n\n   for (i=0; i < count; ++i) {\n      stbtt_uint32 loc = nm + 6 + 12 * i;\n      stbtt_int32 id = ttUSHORT(fc+loc+6);\n      if (id == target_id) {\n         // find the encoding\n         stbtt_int32 platform = ttUSHORT(fc+loc+0), encoding = ttUSHORT(fc+loc+2), language = ttUSHORT(fc+loc+4);\n\n         // is this a Unicode encoding?\n         if (platform == 0 || (platform == 3 && encoding == 1) || (platform == 3 && encoding == 10)) {\n            stbtt_int32 slen = ttUSHORT(fc+loc+8);\n            stbtt_int32 off = ttUSHORT(fc+loc+10);\n\n            // check if there's a prefix match\n            stbtt_int32 matchlen = stbtt__CompareUTF8toUTF16_bigendian_prefix(name, nlen, fc+stringOffset+off,slen);\n            if (matchlen >= 0) {\n               // check for target_id+1 immediately following, with same encoding & language\n               if (i+1 < count && ttUSHORT(fc+loc+12+6) == next_id && ttUSHORT(fc+loc+12) == platform && ttUSHORT(fc+loc+12+2) == encoding && ttUSHORT(fc+loc+12+4) == language) {\n                  slen = ttUSHORT(fc+loc+12+8);\n                  off = ttUSHORT(fc+loc+12+10);\n                  if (slen == 0) {\n                     if (matchlen == nlen)\n                        return 1;\n                  } else if (matchlen < nlen && name[matchlen] == ' ') {\n                     ++matchlen;\n                     if (stbtt_CompareUTF8toUTF16_bigendian_internal((char*) (name+matchlen), nlen-matchlen, (char*)(fc+stringOffset+off),slen))\n                        return 1;\n                  }\n               } else {\n                  // if nothing immediately following\n                  if (matchlen == nlen)\n                     return 1;\n               }\n            }\n         }\n\n         // @TODO handle other encodings\n      }\n   }\n   return 0;\n}\n\nstatic int stbtt__matches(stbtt_uint8 *fc, stbtt_uint32 offset, stbtt_uint8 *name, stbtt_int32 flags)\n{\n   stbtt_int32 nlen = (stbtt_int32) STBTT_strlen((char *) name);\n   stbtt_uint32 nm,hd;\n   if (!stbtt__isfont(fc+offset)) return 0;\n\n   // check italics/bold/underline flags in macStyle...\n   if (flags) {\n      hd = stbtt__find_table(fc, offset, \"head\");\n      if ((ttUSHORT(fc+hd+44) & 7) != (flags & 7)) return 0;\n   }\n\n   nm = stbtt__find_table(fc, offset, \"name\");\n   if (!nm) return 0;\n\n   if (flags) {\n      // if we checked the macStyle flags, then just check the family and ignore the subfamily\n      if (stbtt__matchpair(fc, nm, name, nlen, 16, -1))  return 1;\n      if (stbtt__matchpair(fc, nm, name, nlen,  1, -1))  return 1;\n      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;\n   } else {\n      if (stbtt__matchpair(fc, nm, name, nlen, 16, 17))  return 1;\n      if (stbtt__matchpair(fc, nm, name, nlen,  1,  2))  return 1;\n      if (stbtt__matchpair(fc, nm, name, nlen,  3, -1))  return 1;\n   }\n\n   return 0;\n}\n\nstatic int stbtt_FindMatchingFont_internal(unsigned char *font_collection, char *name_utf8, stbtt_int32 flags)\n{\n   stbtt_int32 i;\n   for (i=0;;++i) {\n      stbtt_int32 off = stbtt_GetFontOffsetForIndex(font_collection, i);\n      if (off < 0) return off;\n      if (stbtt__matches((stbtt_uint8 *) font_collection, off, (stbtt_uint8*) name_utf8, flags))\n         return off;\n   }\n}\n\n#if defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic push\n#pragma GCC diagnostic ignored \"-Wcast-qual\"\n#endif\n\nSTBTT_DEF int stbtt_BakeFontBitmap(const unsigned char *data, int offset,\n                                float pixel_height, unsigned char *pixels, int pw, int ph,\n                                int first_char, int num_chars, stbtt_bakedchar *chardata)\n{\n   return stbtt_BakeFontBitmap_internal((unsigned char *) data, offset, pixel_height, pixels, pw, ph, first_char, num_chars, chardata);\n}\n\nSTBTT_DEF int stbtt_GetFontOffsetForIndex(const unsigned char *data, int index)\n{\n   return stbtt_GetFontOffsetForIndex_internal((unsigned char *) data, index);\n}\n\nSTBTT_DEF int stbtt_GetNumberOfFonts(const unsigned char *data)\n{\n   return stbtt_GetNumberOfFonts_internal((unsigned char *) data);\n}\n\nSTBTT_DEF int stbtt_InitFont(stbtt_fontinfo *info, const unsigned char *data, int offset)\n{\n   return stbtt_InitFont_internal(info, (unsigned char *) data, offset);\n}\n\nSTBTT_DEF int stbtt_FindMatchingFont(const unsigned char *fontdata, const char *name, int flags)\n{\n   return stbtt_FindMatchingFont_internal((unsigned char *) fontdata, (char *) name, flags);\n}\n\nSTBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const char *s2, int len2)\n{\n   return stbtt_CompareUTF8toUTF16_bigendian_internal((char *) s1, len1, (char *) s2, len2);\n}\n\n#if defined(__GNUC__) || defined(__clang__)\n#pragma GCC diagnostic pop\n#endif\n\n#endif // STB_TRUETYPE_IMPLEMENTATION\n\n\n// FULL VERSION HISTORY\n//\n//   1.25 (2021-07-11) many fixes\n//   1.24 (2020-02-05) fix warning\n//   1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)\n//   1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined\n//   1.21 (2019-02-25) fix warning\n//   1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()\n//   1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod\n//   1.18 (2018-01-29) add missing function\n//   1.17 (2017-07-23) make more arguments const; doc fix\n//   1.16 (2017-07-12) SDF support\n//   1.15 (2017-03-03) make more arguments const\n//   1.14 (2017-01-16) num-fonts-in-TTC function\n//   1.13 (2017-01-02) support OpenType fonts, certain Apple fonts\n//   1.12 (2016-10-25) suppress warnings about casting away const with -Wcast-qual\n//   1.11 (2016-04-02) fix unused-variable warning\n//   1.10 (2016-04-02) allow user-defined fabs() replacement\n//                     fix memory leak if fontsize=0.0\n//                     fix warning from duplicate typedef\n//   1.09 (2016-01-16) warning fix; avoid crash on outofmem; use alloc userdata for PackFontRanges\n//   1.08 (2015-09-13) document stbtt_Rasterize(); fixes for vertical & horizontal edges\n//   1.07 (2015-08-01) allow PackFontRanges to accept arrays of sparse codepoints;\n//                     allow PackFontRanges to pack and render in separate phases;\n//                     fix stbtt_GetFontOFfsetForIndex (never worked for non-0 input?);\n//                     fixed an assert() bug in the new rasterizer\n//                     replace assert() with STBTT_assert() in new rasterizer\n//   1.06 (2015-07-14) performance improvements (~35% faster on x86 and x64 on test machine)\n//                     also more precise AA rasterizer, except if shapes overlap\n//                     remove need for STBTT_sort\n//   1.05 (2015-04-15) fix misplaced definitions for STBTT_STATIC\n//   1.04 (2015-04-15) typo in example\n//   1.03 (2015-04-12) STBTT_STATIC, fix memory leak in new packing, various fixes\n//   1.02 (2014-12-10) fix various warnings & compile issues w/ stb_rect_pack, C++\n//   1.01 (2014-12-08) fix subpixel position when oversampling to exactly match\n//                        non-oversampled; STBTT_POINT_SIZE for packed case only\n//   1.00 (2014-12-06) add new PackBegin etc. API, w/ support for oversampling\n//   0.99 (2014-09-18) fix multiple bugs with subpixel rendering (ryg)\n//   0.9  (2014-08-07) support certain mac/iOS fonts without an MS platformID\n//   0.8b (2014-07-07) fix a warning\n//   0.8  (2014-05-25) fix a few more warnings\n//   0.7  (2013-09-25) bugfix: subpixel glyph bug fixed in 0.5 had come back\n//   0.6c (2012-07-24) improve documentation\n//   0.6b (2012-07-20) fix a few more warnings\n//   0.6  (2012-07-17) fix warnings; added stbtt_ScaleForMappingEmToPixels,\n//                        stbtt_GetFontBoundingBox, stbtt_IsGlyphEmpty\n//   0.5  (2011-12-09) bugfixes:\n//                        subpixel glyph renderer computed wrong bounding box\n//                        first vertex of shape can be off-curve (FreeSans)\n//   0.4b (2011-12-03) fixed an error in the font baking example\n//   0.4  (2011-12-01) kerning, subpixel rendering (tor)\n//                    bugfixes for:\n//                        codepoint-to-glyph conversion using table fmt=12\n//                        codepoint-to-glyph conversion using table fmt=4\n//                        stbtt_GetBakedQuad with non-square texture (Zer)\n//                    updated Hello World! sample to use kerning and subpixel\n//                    fixed some warnings\n//   0.3  (2009-06-24) cmap fmt=12, compound shapes (MM)\n//                    userdata, malloc-from-userdata, non-zero fill (stb)\n//   0.2  (2009-03-11) Fix unsigned/signed char warnings\n//   0.1  (2009-03-09) First public release\n//\n\n/*\n------------------------------------------------------------------------------\nThis software is available under 2 licenses -- choose whichever you prefer.\n------------------------------------------------------------------------------\nALTERNATIVE A - MIT License\nCopyright (c) 2017 Sean Barrett\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\nof the Software, and to permit persons to whom the Software is furnished to do\nso, subject to the following conditions:\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n------------------------------------------------------------------------------\nALTERNATIVE B - Public Domain (www.unlicense.org)\nThis is free and unencumbered software released into the public domain.\nAnyone is free to copy, modify, publish, use, compile, sell, or distribute this\nsoftware, either in source code form or as a compiled binary, for any purpose,\ncommercial or non-commercial, and by any means.\nIn jurisdictions that recognize copyright laws, the author or authors of this\nsoftware dedicate any and all copyright interest in the software to the public\ndomain. We make this dedication for the benefit of the public at large and to\nthe detriment of our heirs and successors. We intend this dedication to be an\novert act of relinquishment in perpetuity of all present and future rights to\nthis software under copyright law.\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\nACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n------------------------------------------------------------------------------\n*/\n"
  }
]